2008-07-22 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  */
10
11 #include <config.h>
12 #include <signal.h>
13
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <math.h>
19
20 #ifdef HAVE_SYS_TIME_H
21 #include <sys/time.h>
22 #endif
23
24 #ifdef HAVE_VALGRIND_MEMCHECK_H
25 #include <valgrind/memcheck.h>
26 #endif
27
28 #include <mono/metadata/assembly.h>
29 #include <mono/metadata/loader.h>
30 #include <mono/metadata/tabledefs.h>
31 #include <mono/metadata/class.h>
32 #include <mono/metadata/object.h>
33 #include <mono/metadata/exception.h>
34 #include <mono/metadata/opcodes.h>
35 #include <mono/metadata/mono-endian.h>
36 #include <mono/metadata/tokentype.h>
37 #include <mono/metadata/tabledefs.h>
38 #include <mono/metadata/threads.h>
39 #include <mono/metadata/marshal.h>
40 #include <mono/metadata/socket-io.h>
41 #include <mono/metadata/appdomain.h>
42 #include <mono/metadata/debug-helpers.h>
43 #include <mono/io-layer/io-layer.h>
44 #include "mono/metadata/profiler.h"
45 #include <mono/metadata/profiler-private.h>
46 #include <mono/metadata/mono-config.h>
47 #include <mono/metadata/environment.h>
48 #include <mono/metadata/mono-debug.h>
49 #include <mono/metadata/mono-debug-debugger.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/gc-internal.h>
52 #include <mono/metadata/security-manager.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/rawbuffer.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/utils/mono-math.h>
57 #include <mono/utils/mono-compiler.h>
58 #include <mono/os/gc_wrapper.h>
59
60 #define NEW_IR
61 #include "mini.h"
62 #include <string.h>
63 #include <ctype.h>
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69
70 #include "aliasing.h"
71
72 #define BRANCH_COST 100
73 #define INLINE_LENGTH_LIMIT 20
74 #define INLINE_FAILURE do {\
75                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
76                         goto inline_failure;\
77         } while (0)
78 #define CHECK_CFG_EXCEPTION do {\
79                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
80                         goto exception_exit;\
81         } while (0)
82 #define METHOD_ACCESS_FAILURE do {      \
83                 char *method_fname = mono_method_full_name (method, TRUE);      \
84                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
85                 cfg->exception_type = MONO_EXCEPTION_METHOD_ACCESS;     \
86                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
87                 g_free (method_fname);  \
88                 g_free (cil_method_fname);      \
89                 goto exception_exit;    \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE do {       \
92                 char *method_fname = mono_method_full_name (method, TRUE);      \
93                 char *field_fname = mono_field_full_name (field);       \
94                 cfg->exception_type = MONO_EXCEPTION_FIELD_ACCESS;      \
95                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
96                 g_free (method_fname);  \
97                 g_free (field_fname);   \
98                 goto exception_exit;    \
99         } while (0)
100 #define GENERIC_SHARING_FAILURE(opcode) do {            \
101                 if (cfg->generic_sharing_context) {     \
102             if (cfg->verbose_level > -1) \
103                             printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
104                         cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;    \
105                         goto exception_exit;    \
106                 }                       \
107         } while (0)
108 #define GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(opcode) do {                        \
109                 if (method->klass->valuetype)   \
110                         GENERIC_SHARING_FAILURE ((opcode)); \
111         } while (0)
112
113 /* Determine whenever 'ins' represents a load of the 'this' argument */
114 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
115
116 static int ldind_to_load_membase (int opcode);
117 static int stind_to_store_membase (int opcode);
118
119 int mono_op_to_op_imm (int opcode);
120 int mono_op_to_op_imm_noemul (int opcode);
121
122 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
123 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
124 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
125
126 int mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
127                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
128                    guint inline_offset, gboolean is_virtual_call);
129
130 /* helper methods signature */
131 MonoMethodSignature *helper_sig_class_init_trampoline;
132 MonoMethodSignature *helper_sig_domain_get;
133 MonoMethodSignature *helper_sig_generic_class_init_trampoline;
134 MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
135
136 /*
137  * Instruction metadata
138  */
139 #ifdef MINI_OP
140 #undef MINI_OP
141 #endif
142 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2,
143 #define NONE ' '
144 #define IREG 'i'
145 #define FREG 'f'
146 #define VREG 'v'
147 #if SIZEOF_VOID_P == 8
148 #define LREG IREG
149 #else
150 #define LREG 'l'
151 #endif
152 /* keep in sync with the enum in mini.h */
153 const char
154 ins_info[] = {
155 #include "mini-ops.h"
156 };
157 #undef MINI_OP
158
159 extern GHashTable *jit_icall_name_hash;
160
161 #define MONO_INIT_VARINFO(vi,id) do { \
162         (vi)->range.first_use.pos.bid = 0xffff; \
163         (vi)->reg = -1; \
164         (vi)->idx = (id); \
165 } while (0)
166
167 guint32
168 mono_alloc_ireg (MonoCompile *cfg)
169 {
170         return alloc_ireg (cfg);
171 }
172
173 guint32
174 mono_alloc_freg (MonoCompile *cfg)
175 {
176         return alloc_freg (cfg);
177 }
178
179 guint32
180 mono_alloc_preg (MonoCompile *cfg)
181 {
182         return alloc_preg (cfg);
183 }
184
185 guint32
186 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
187 {
188         return alloc_dreg (cfg, stack_type);
189 }
190
191 static guint
192 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
193 {
194         if (type->byref)
195                 return OP_MOVE;
196
197 handle_enum:
198         switch (type->type) {
199         case MONO_TYPE_I1:
200         case MONO_TYPE_U1:
201         case MONO_TYPE_BOOLEAN:
202                 return OP_MOVE;
203         case MONO_TYPE_I2:
204         case MONO_TYPE_U2:
205         case MONO_TYPE_CHAR:
206                 return OP_MOVE;
207         case MONO_TYPE_I4:
208         case MONO_TYPE_U4:
209                 return OP_MOVE;
210         case MONO_TYPE_I:
211         case MONO_TYPE_U:
212         case MONO_TYPE_PTR:
213         case MONO_TYPE_FNPTR:
214                 return OP_MOVE;
215         case MONO_TYPE_CLASS:
216         case MONO_TYPE_STRING:
217         case MONO_TYPE_OBJECT:
218         case MONO_TYPE_SZARRAY:
219         case MONO_TYPE_ARRAY:    
220                 return OP_MOVE;
221         case MONO_TYPE_I8:
222         case MONO_TYPE_U8:
223 #if SIZEOF_VOID_P == 8
224                 return OP_MOVE;
225 #else
226                 return OP_LMOVE;
227 #endif
228         case MONO_TYPE_R4:
229                 return OP_FMOVE;
230         case MONO_TYPE_R8:
231                 return OP_FMOVE;
232         case MONO_TYPE_VALUETYPE:
233                 if (type->data.klass->enumtype) {
234                         type = type->data.klass->enum_basetype;
235                         goto handle_enum;
236                 }
237                 return OP_VMOVE;
238         case MONO_TYPE_TYPEDBYREF:
239                 return OP_VMOVE;
240         case MONO_TYPE_GENERICINST:
241                 type = &type->data.generic_class->container_class->byval_arg;
242                 goto handle_enum;
243         case MONO_TYPE_VAR:
244         case MONO_TYPE_MVAR:
245                 g_assert (cfg->generic_sharing_context);
246                 return OP_MOVE;
247         default:
248                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
249         }
250         return -1;
251 }
252
253 void
254 mono_print_bb (MonoBasicBlock *bb, const char *msg)
255 {
256         int i;
257         MonoInst *tree;
258
259         printf ("\n%s %d: [IN: ", msg, bb->block_num);
260         for (i = 0; i < bb->in_count; ++i)
261                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
262         printf (", OUT: ");
263         for (i = 0; i < bb->out_count; ++i)
264                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
265         printf (" ]\n");
266         for (tree = bb->code; tree; tree = tree->next)
267                 mono_print_ins_index (-1, tree);
268 }
269
270 #define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
271
272 #define GET_BBLOCK(cfg,tblock,ip) do {  \
273                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
274                 if (!(tblock)) {        \
275                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
276             NEW_BBLOCK (cfg, (tblock)); \
277                         (tblock)->cil_code = (ip);      \
278                         ADD_BBLOCK (cfg, (tblock));     \
279                 } \
280         } while (0)
281
282 #define CHECK_BBLOCK(target,ip,tblock) do {     \
283                 if ((target) < (ip) && !(tblock)->code) {       \
284                         bb_recheck = g_list_prepend (bb_recheck, (tblock));     \
285                         if (cfg->verbose_level > 2) printf ("queued block %d for check at IL%04x from IL%04x\n", (tblock)->block_num, (int)((target) - header->code), (int)((ip) - header->code));      \
286                 }       \
287         } while (0)
288
289 #ifndef MONO_ARCH_EMIT_BOUNDS_CHECK
290 #define MONO_ARCH_EMIT_BOUNDS_CHECK(cfg, array_reg, offset, index_reg) do { \
291                         int _length_reg = alloc_ireg (cfg); \
292                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, _length_reg, array_reg, offset); \
293                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, _length_reg, index_reg); \
294                         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException"); \
295         } while (0)
296 #endif
297
298 #define MONO_EMIT_BOUNDS_CHECK(cfg, array_reg, array_type, array_length_field, index_reg) do { \
299             if (!(cfg->opt & MONO_OPT_ABCREM)) { \
300                 MONO_ARCH_EMIT_BOUNDS_CHECK ((cfg), (array_reg), G_STRUCT_OFFSET (array_type, array_length_field), (index_reg)); \
301             } else { \
302                 MonoInst *ins; \
303                 MONO_INST_NEW ((cfg), ins, OP_BOUNDS_CHECK); \
304                 ins->sreg1 = array_reg; \
305                 ins->sreg2 = index_reg; \
306                 ins->inst_imm = G_STRUCT_OFFSET (array_type, array_length_field); \
307                 MONO_ADD_INS ((cfg)->cbb, ins); \
308                             (cfg)->flags |= MONO_CFG_HAS_ARRAY_ACCESS; \
309                 (cfg)->cbb->has_array_access = TRUE; \
310             } \
311     } while (0)
312
313 #if defined(__i386__) || defined(__x86_64__)
314 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
315                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
316                 (dest)->dreg = alloc_preg ((cfg)); \
317                 (dest)->sreg1 = (sr1); \
318                 (dest)->sreg2 = (sr2); \
319                 (dest)->inst_imm = (imm); \
320                 (dest)->backend.shift_amount = (shift); \
321                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
322         } while (0)
323 #endif
324
325 #if SIZEOF_VOID_P == 8
326 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
327                 /* FIXME: Need to add many more cases */ \
328                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) { \
329                         MonoInst *widen; \
330                         int dr = alloc_preg (cfg); \
331                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
332                         (ins)->sreg2 = widen->dreg; \
333                 } \
334         } while (0)
335 #else
336 #define ADD_WIDEN_OP(arg1, arg2)
337 #endif
338
339 #define ADD_BINOP(op) do {      \
340                 MONO_INST_NEW (cfg, ins, (op)); \
341                 sp -= 2;        \
342                 ins->sreg1 = sp [0]->dreg;      \
343                 ins->sreg2 = sp [1]->dreg;      \
344                 type_from_op (ins, sp [0], sp [1]);     \
345                 CHECK_TYPE (ins);       \
346                 /* Have to insert a widening op */               \
347         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
348         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
349         MONO_ADD_INS ((cfg)->cbb, (ins)); \
350                 *sp++ = ins;    \
351         mono_decompose_opcode ((cfg), (ins)); \
352         } while (0)
353
354 #define ADD_UNOP(op) do {       \
355                 MONO_INST_NEW (cfg, ins, (op)); \
356                 sp--;   \
357                 ins->sreg1 = sp [0]->dreg;      \
358                 type_from_op (ins, sp [0], NULL);       \
359                 CHECK_TYPE (ins);       \
360         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
361         MONO_ADD_INS ((cfg)->cbb, (ins)); \
362                 *sp++ = ins;    \
363                 mono_decompose_opcode (cfg, ins); \
364         } while (0)
365
366 #define ADD_BINCOND(next_block) do {    \
367                 MonoInst *cmp;  \
368                 sp -= 2; \
369                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
370                 cmp->sreg1 = sp [0]->dreg;      \
371                 cmp->sreg2 = sp [1]->dreg;      \
372                 type_from_op (cmp, sp [0], sp [1]);     \
373                 CHECK_TYPE (cmp);       \
374                 type_from_op (ins, sp [0], sp [1]);     \
375                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
376                 GET_BBLOCK (cfg, tblock, target);               \
377                 link_bblock (cfg, bblock, tblock);      \
378                 ins->inst_true_bb = tblock;     \
379                 CHECK_BBLOCK (target, ip, tblock);      \
380                 if ((next_block)) {     \
381                         link_bblock (cfg, bblock, (next_block));        \
382                         ins->inst_false_bb = (next_block);      \
383                         start_new_bblock = 1;   \
384                 } else {        \
385                         GET_BBLOCK (cfg, tblock, ip);           \
386                         link_bblock (cfg, bblock, tblock);      \
387                         ins->inst_false_bb = tblock;    \
388                         start_new_bblock = 2;   \
389                 }       \
390                 if (sp != stack_start) {                                                                        \
391                     handle_stack_args (cfg, stack_start, sp - stack_start); \
392                         CHECK_UNVERIFIABLE (cfg); \
393                 } \
394         MONO_ADD_INS (bblock, cmp); \
395                 MONO_ADD_INS (bblock, ins);     \
396         } while (0)
397
398 /* *
399  * link_bblock: Links two basic blocks
400  *
401  * links two basic blocks in the control flow graph, the 'from'
402  * argument is the starting block and the 'to' argument is the block
403  * the control flow ends to after 'from'.
404  */
405 static void
406 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
407 {
408         MonoBasicBlock **newa;
409         int i, found;
410
411 #if 0
412         if (from->cil_code) {
413                 if (to->cil_code)
414                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
415                 else
416                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
417         } else {
418                 if (to->cil_code)
419                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
420                 else
421                         printf ("edge from entry to exit\n");
422         }
423 #endif
424
425         found = FALSE;
426         for (i = 0; i < from->out_count; ++i) {
427                 if (to == from->out_bb [i]) {
428                         found = TRUE;
429                         break;
430                 }
431         }
432         if (!found) {
433                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
434                 for (i = 0; i < from->out_count; ++i) {
435                         newa [i] = from->out_bb [i];
436                 }
437                 newa [i] = to;
438                 from->out_count++;
439                 from->out_bb = newa;
440         }
441
442         found = FALSE;
443         for (i = 0; i < to->in_count; ++i) {
444                 if (from == to->in_bb [i]) {
445                         found = TRUE;
446                         break;
447                 }
448         }
449         if (!found) {
450                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
451                 for (i = 0; i < to->in_count; ++i) {
452                         newa [i] = to->in_bb [i];
453                 }
454                 newa [i] = from;
455                 to->in_count++;
456                 to->in_bb = newa;
457         }
458 }
459
460 void
461 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
462 {
463         link_bblock (cfg, from, to);
464 }
465
466 /**
467  * mono_find_block_region:
468  *
469  *   We mark each basic block with a region ID. We use that to avoid BB
470  *   optimizations when blocks are in different regions.
471  *
472  * Returns:
473  *   A region token that encodes where this region is, and information
474  *   about the clause owner for this block.
475  *
476  *   The region encodes the try/catch/filter clause that owns this block
477  *   as well as the type.  -1 is a special value that represents a block
478  *   that is in none of try/catch/filter.
479  */
480 static int
481 mono_find_block_region (MonoCompile *cfg, int offset)
482 {
483         MonoMethod *method = cfg->method;
484         MonoMethodHeader *header = mono_method_get_header (method);
485         MonoExceptionClause *clause;
486         int i;
487
488         /* first search for handlers and filters */
489         for (i = 0; i < header->num_clauses; ++i) {
490                 clause = &header->clauses [i];
491                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
492                     (offset < (clause->handler_offset)))
493                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
494                            
495                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
496                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
497                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
498                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
499                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
500                         else
501                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
502                 }
503         }
504
505         /* search the try blocks */
506         for (i = 0; i < header->num_clauses; ++i) {
507                 clause = &header->clauses [i];
508                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
509                         return ((i + 1) << 8) | clause->flags;
510         }
511
512         return -1;
513 }
514
515 static GList*
516 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
517 {
518         MonoMethod *method = cfg->method;
519         MonoMethodHeader *header = mono_method_get_header (method);
520         MonoExceptionClause *clause;
521         MonoBasicBlock *handler;
522         int i;
523         GList *res = NULL;
524
525         for (i = 0; i < header->num_clauses; ++i) {
526                 clause = &header->clauses [i];
527                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
528                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
529                         if (clause->flags == type) {
530                                 handler = cfg->cil_offset_to_bb [clause->handler_offset];
531                                 g_assert (handler);
532                                 res = g_list_append (res, handler);
533                         }
534                 }
535         }
536         return res;
537 }
538
539 static void
540 mono_create_spvar_for_region (MonoCompile *cfg, int region)
541 {
542         MonoInst *var;
543
544         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
545         if (var)
546                 return;
547
548         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
549         /* prevent it from being register allocated */
550         var->flags |= MONO_INST_INDIRECT;
551
552         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
553 }
554
555 static MonoInst *
556 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
557 {
558         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
559 }
560
561 static MonoInst*
562 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
563 {
564         MonoInst *var;
565
566         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
567         if (var)
568                 return var;
569
570         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
571         /* prevent it from being register allocated */
572         var->flags |= MONO_INST_INDIRECT;
573
574         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
575
576         return var;
577 }
578
579 static MonoBasicBlock*
580 find_previous (MonoBasicBlock **bblocks, guint32 n_bblocks, MonoBasicBlock *start, const guchar *code)
581 {
582         MonoBasicBlock *best = start;
583         int i;
584
585         for (i = 0; i < n_bblocks; ++i) {
586                 if (bblocks [i]) {
587                         MonoBasicBlock *bb = bblocks [i];
588
589                         if (bb->cil_code && bb->cil_code < code && bb->cil_code > best->cil_code)
590                                 best = bb;
591                 }
592         }
593
594         return best;
595 }
596
597 static void
598 split_bblock (MonoCompile *cfg, MonoBasicBlock *first, MonoBasicBlock *second) {
599         int i, j;
600         MonoInst *inst;
601         MonoBasicBlock *bb;
602
603         if (second->code)
604                 return;
605         
606         /* 
607          * FIXME: take into account all the details:
608          * second may have been the target of more than one bblock
609          */
610         second->out_count = first->out_count;
611         second->out_bb = first->out_bb;
612
613         for (i = 0; i < first->out_count; ++i) {
614                 bb = first->out_bb [i];
615                 for (j = 0; j < bb->in_count; ++j) {
616                         if (bb->in_bb [j] == first)
617                                 bb->in_bb [j] = second;
618                 }
619         }
620
621         first->out_count = 0;
622         first->out_bb = NULL;
623         link_bblock (cfg, first, second);
624
625         second->last_ins = first->last_ins;
626
627         /*printf ("start search at %p for %p\n", first->cil_code, second->cil_code);*/
628         for (inst = first->code; inst && inst->next; inst = inst->next) {
629                 /*char *code = mono_disasm_code_one (NULL, cfg->method, inst->next->cil_code, NULL);
630                 printf ("found %p: %s", inst->next->cil_code, code);
631                 g_free (code);*/
632                 if (inst->cil_code < second->cil_code && inst->next->cil_code >= second->cil_code) {
633                         second->code = inst->next;
634                         inst->next = NULL;
635                         first->last_ins = inst;
636                         second->next_bb = first->next_bb;
637                         first->next_bb = second;
638                         return;
639                 }
640         }
641         if (!second->code) {
642                 g_warning ("bblock split failed in %s::%s\n", cfg->method->klass->name, cfg->method->name);
643                 //G_BREAKPOINT ();
644         }
645 }
646
647 /*
648  * Returns the type used in the eval stack when @type is loaded.
649  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
650  */
651 static void
652 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
653 {
654         MonoClass *klass;
655
656         if (type->byref) {
657                 inst->type = STACK_MP;
658                 inst->klass = mono_defaults.object_class;
659                 return;
660         }
661
662         inst->klass = klass = mono_class_from_mono_type (type);
663
664 handle_enum:
665         switch (type->type) {
666         case MONO_TYPE_VOID:
667                 inst->type = STACK_INV;
668                 return;
669         case MONO_TYPE_I1:
670         case MONO_TYPE_U1:
671         case MONO_TYPE_BOOLEAN:
672         case MONO_TYPE_I2:
673         case MONO_TYPE_U2:
674         case MONO_TYPE_CHAR:
675         case MONO_TYPE_I4:
676         case MONO_TYPE_U4:
677                 inst->type = STACK_I4;
678                 return;
679         case MONO_TYPE_I:
680         case MONO_TYPE_U:
681         case MONO_TYPE_PTR:
682         case MONO_TYPE_FNPTR:
683                 inst->type = STACK_PTR;
684                 return;
685         case MONO_TYPE_CLASS:
686         case MONO_TYPE_STRING:
687         case MONO_TYPE_OBJECT:
688         case MONO_TYPE_SZARRAY:
689         case MONO_TYPE_ARRAY:    
690                 inst->type = STACK_OBJ;
691                 return;
692         case MONO_TYPE_I8:
693         case MONO_TYPE_U8:
694                 inst->type = STACK_I8;
695                 return;
696         case MONO_TYPE_R4:
697         case MONO_TYPE_R8:
698                 inst->type = STACK_R8;
699                 return;
700         case MONO_TYPE_VALUETYPE:
701                 if (type->data.klass->enumtype) {
702                         type = type->data.klass->enum_basetype;
703                         goto handle_enum;
704                 } else {
705                         inst->klass = klass;
706                         inst->type = STACK_VTYPE;
707                         return;
708                 }
709         case MONO_TYPE_TYPEDBYREF:
710                 inst->klass = mono_defaults.typed_reference_class;
711                 inst->type = STACK_VTYPE;
712                 return;
713         case MONO_TYPE_GENERICINST:
714                 type = &type->data.generic_class->container_class->byval_arg;
715                 goto handle_enum;
716         case MONO_TYPE_VAR :
717         case MONO_TYPE_MVAR :
718                 /* FIXME: all the arguments must be references for now,
719                  * later look inside cfg and see if the arg num is
720                  * really a reference
721                  */
722                 g_assert (cfg->generic_sharing_context);
723                 inst->type = STACK_OBJ;
724                 return;
725         default:
726                 g_error ("unknown type 0x%02x in eval stack type", type->type);
727         }
728 }
729
730 /*
731  * The following tables are used to quickly validate the IL code in type_from_op ().
732  */
733 static const char
734 bin_num_table [STACK_MAX] [STACK_MAX] = {
735         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
736         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
737         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
738         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
739         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
740         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
741         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
742         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
743 };
744
745 static const char 
746 neg_table [] = {
747         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
748 };
749
750 /* reduce the size of this table */
751 static const char
752 bin_int_table [STACK_MAX] [STACK_MAX] = {
753         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
754         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
755         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
756         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
757         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
758         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
759         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
760         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
761 };
762
763 static const char
764 bin_comp_table [STACK_MAX] [STACK_MAX] = {
765 /*      Inv i  L  p  F  &  O  vt */
766         {0},
767         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
768         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
769         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
770         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
771         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
772         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
773         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
774 };
775
776 /* reduce the size of this table */
777 static const char
778 shift_table [STACK_MAX] [STACK_MAX] = {
779         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
780         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
781         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
782         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
783         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
784         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
785         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
786         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
787 };
788
789 /*
790  * Tables to map from the non-specific opcode to the matching
791  * type-specific opcode.
792  */
793 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
794 static const guint16
795 binops_op_map [STACK_MAX] = {
796         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
797 };
798
799 /* handles from CEE_NEG to CEE_CONV_U8 */
800 static const guint16
801 unops_op_map [STACK_MAX] = {
802         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
803 };
804
805 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
806 static const guint16
807 ovfops_op_map [STACK_MAX] = {
808         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2
809 };
810
811 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
812 static const guint16
813 ovf2ops_op_map [STACK_MAX] = {
814         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
815 };
816
817 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
818 static const guint16
819 ovf3ops_op_map [STACK_MAX] = {
820         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1
821 };
822
823 /* handles from CEE_BEQ to CEE_BLT_UN */
824 static const guint16
825 beqops_op_map [STACK_MAX] = {
826         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ
827 };
828
829 /* handles from CEE_CEQ to CEE_CLT_UN */
830 static const guint16
831 ceqops_op_map [STACK_MAX] = {
832         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ
833 };
834
835 /*
836  * Sets ins->type (the type on the eval stack) according to the
837  * type of the opcode and the arguments to it.
838  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
839  *
840  * FIXME: this function sets ins->type unconditionally in some cases, but
841  * it should set it to invalid for some types (a conv.x on an object)
842  */
843 static void
844 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
845
846         switch (ins->opcode) {
847         /* binops */
848         case CEE_ADD:
849         case CEE_SUB:
850         case CEE_MUL:
851         case CEE_DIV:
852         case CEE_REM:
853                 /* FIXME: check unverifiable args for STACK_MP */
854                 ins->type = bin_num_table [src1->type] [src2->type];
855                 ins->opcode += binops_op_map [ins->type];
856                 break;
857         case CEE_DIV_UN:
858         case CEE_REM_UN:
859         case CEE_AND:
860         case CEE_OR:
861         case CEE_XOR:
862                 ins->type = bin_int_table [src1->type] [src2->type];
863                 ins->opcode += binops_op_map [ins->type];
864                 break;
865         case CEE_SHL:
866         case CEE_SHR:
867         case CEE_SHR_UN:
868                 ins->type = shift_table [src1->type] [src2->type];
869                 ins->opcode += binops_op_map [ins->type];
870                 break;
871         case OP_COMPARE:
872         case OP_LCOMPARE:
873         case OP_ICOMPARE:
874                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
875                 if ((src1->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
876                         ins->opcode = OP_LCOMPARE;
877                 else if (src1->type == STACK_R8)
878                         ins->opcode = OP_FCOMPARE;
879                 else
880                         ins->opcode = OP_ICOMPARE;
881                 break;
882         case OP_ICOMPARE_IMM:
883                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
884                 if ((src1->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
885                         ins->opcode = OP_LCOMPARE_IMM;          
886                 break;
887         case CEE_BEQ:
888         case CEE_BGE:
889         case CEE_BGT:
890         case CEE_BLE:
891         case CEE_BLT:
892         case CEE_BNE_UN:
893         case CEE_BGE_UN:
894         case CEE_BGT_UN:
895         case CEE_BLE_UN:
896         case CEE_BLT_UN:
897                 ins->opcode += beqops_op_map [src1->type];
898                 break;
899         case OP_CEQ:
900                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
901                 ins->opcode += ceqops_op_map [src1->type];
902                 break;
903         case OP_CGT:
904         case OP_CGT_UN:
905         case OP_CLT:
906         case OP_CLT_UN:
907                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
908                 ins->opcode += ceqops_op_map [src1->type];
909                 break;
910         /* unops */
911         case CEE_NEG:
912                 ins->type = neg_table [src1->type];
913                 ins->opcode += unops_op_map [ins->type];
914                 break;
915         case CEE_NOT:
916                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
917                         ins->type = src1->type;
918                 else
919                         ins->type = STACK_INV;
920                 ins->opcode += unops_op_map [ins->type];
921                 break;
922         case CEE_CONV_I1:
923         case CEE_CONV_I2:
924         case CEE_CONV_I4:
925         case CEE_CONV_U4:
926                 ins->type = STACK_I4;
927                 ins->opcode += unops_op_map [src1->type];
928                 break;
929         case CEE_CONV_R_UN:
930                 ins->type = STACK_R8;
931                 switch (src1->type) {
932                 case STACK_I4:
933                 case STACK_PTR:
934                         ins->opcode = OP_ICONV_TO_R_UN;
935                         break;
936                 case STACK_I8:
937                         ins->opcode = OP_LCONV_TO_R_UN; 
938                         break;
939                 }
940                 break;
941         case CEE_CONV_OVF_I1:
942         case CEE_CONV_OVF_U1:
943         case CEE_CONV_OVF_I2:
944         case CEE_CONV_OVF_U2:
945         case CEE_CONV_OVF_I4:
946         case CEE_CONV_OVF_U4:
947                 ins->type = STACK_I4;
948                 ins->opcode += ovf3ops_op_map [src1->type];
949                 break;
950         case CEE_CONV_OVF_I_UN:
951         case CEE_CONV_OVF_U_UN:
952                 ins->type = STACK_PTR;
953                 ins->opcode += ovf2ops_op_map [src1->type];
954                 break;
955         case CEE_CONV_OVF_I1_UN:
956         case CEE_CONV_OVF_I2_UN:
957         case CEE_CONV_OVF_I4_UN:
958         case CEE_CONV_OVF_U1_UN:
959         case CEE_CONV_OVF_U2_UN:
960         case CEE_CONV_OVF_U4_UN:
961                 ins->type = STACK_I4;
962                 ins->opcode += ovf2ops_op_map [src1->type];
963                 break;
964         case CEE_CONV_U:
965                 ins->type = STACK_PTR;
966                 switch (src1->type) {
967                 case STACK_I4:
968                         ins->opcode = OP_MOVE;
969                         break;
970                 case STACK_PTR:
971                 case STACK_MP:
972 #if SIZEOF_VOID_P == 8
973                         ins->opcode = OP_LCONV_TO_U;
974 #else
975                         ins->opcode = OP_MOVE;
976 #endif
977                         break;
978                 case STACK_I8:
979                         ins->opcode = OP_LCONV_TO_U;
980                         break;
981                 case STACK_R8:
982                         ins->opcode = OP_FCONV_TO_U;
983                         break;
984                 }
985                 break;
986         case CEE_CONV_I8:
987         case CEE_CONV_U8:
988                 ins->type = STACK_I8;
989                 ins->opcode += unops_op_map [src1->type];
990                 break;
991         case CEE_CONV_OVF_I8:
992         case CEE_CONV_OVF_U8:
993                 ins->type = STACK_I8;
994                 ins->opcode += ovf3ops_op_map [src1->type];
995                 break;
996         case CEE_CONV_OVF_U8_UN:
997         case CEE_CONV_OVF_I8_UN:
998                 ins->type = STACK_I8;
999                 ins->opcode += ovf2ops_op_map [src1->type];
1000                 break;
1001         case CEE_CONV_R4:
1002         case CEE_CONV_R8:
1003                 ins->type = STACK_R8;
1004                 ins->opcode += unops_op_map [src1->type];
1005                 break;
1006         case OP_CKFINITE:
1007                 ins->type = STACK_R8;           
1008                 break;
1009         case CEE_CONV_U2:
1010         case CEE_CONV_U1:
1011                 ins->type = STACK_I4;
1012                 ins->opcode += ovfops_op_map [src1->type];
1013                 break;
1014         case CEE_CONV_I:
1015         case CEE_CONV_OVF_I:
1016         case CEE_CONV_OVF_U:
1017                 ins->type = STACK_PTR;
1018                 ins->opcode += ovfops_op_map [src1->type];
1019                 break;
1020         case CEE_ADD_OVF:
1021         case CEE_ADD_OVF_UN:
1022         case CEE_MUL_OVF:
1023         case CEE_MUL_OVF_UN:
1024         case CEE_SUB_OVF:
1025         case CEE_SUB_OVF_UN:
1026                 ins->type = bin_num_table [src1->type] [src2->type];
1027                 ins->opcode += ovfops_op_map [src1->type];
1028                 if (ins->type == STACK_R8)
1029                         ins->type = STACK_INV;
1030                 break;
1031         case OP_LOAD_MEMBASE:
1032                 ins->type = STACK_PTR;
1033                 break;
1034         case OP_LOADI1_MEMBASE:
1035         case OP_LOADU1_MEMBASE:
1036         case OP_LOADI2_MEMBASE:
1037         case OP_LOADU2_MEMBASE:
1038         case OP_LOADI4_MEMBASE:
1039         case OP_LOADU4_MEMBASE:
1040                 ins->type = STACK_PTR;
1041                 break;
1042         case OP_LOADI8_MEMBASE:
1043                 ins->type = STACK_I8;
1044                 break;
1045         case OP_LOADR4_MEMBASE:
1046         case OP_LOADR8_MEMBASE:
1047                 ins->type = STACK_R8;
1048                 break;
1049         default:
1050                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1051                 break;
1052         }
1053
1054         if (ins->type == STACK_MP)
1055                 ins->klass = mono_defaults.object_class;
1056 }
1057
1058 static const char 
1059 ldind_type [] = {
1060         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1061 };
1062
1063 #if 0
1064
1065 static const char
1066 param_table [STACK_MAX] [STACK_MAX] = {
1067         {0},
1068 };
1069
1070 static int
1071 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1072         int i;
1073
1074         if (sig->hasthis) {
1075                 switch (args->type) {
1076                 case STACK_I4:
1077                 case STACK_I8:
1078                 case STACK_R8:
1079                 case STACK_VTYPE:
1080                 case STACK_INV:
1081                         return 0;
1082                 }
1083                 args++;
1084         }
1085         for (i = 0; i < sig->param_count; ++i) {
1086                 switch (args [i].type) {
1087                 case STACK_INV:
1088                         return 0;
1089                 case STACK_MP:
1090                         if (!sig->params [i]->byref)
1091                                 return 0;
1092                         continue;
1093                 case STACK_OBJ:
1094                         if (sig->params [i]->byref)
1095                                 return 0;
1096                         switch (sig->params [i]->type) {
1097                         case MONO_TYPE_CLASS:
1098                         case MONO_TYPE_STRING:
1099                         case MONO_TYPE_OBJECT:
1100                         case MONO_TYPE_SZARRAY:
1101                         case MONO_TYPE_ARRAY:
1102                                 break;
1103                         default:
1104                                 return 0;
1105                         }
1106                         continue;
1107                 case STACK_R8:
1108                         if (sig->params [i]->byref)
1109                                 return 0;
1110                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1111                                 return 0;
1112                         continue;
1113                 case STACK_PTR:
1114                 case STACK_I4:
1115                 case STACK_I8:
1116                 case STACK_VTYPE:
1117                         break;
1118                 }
1119                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1120                         return 0;*/
1121         }
1122         return 1;
1123 }
1124 #endif
1125
1126 /*
1127  * When we need a pointer to the current domain many times in a method, we
1128  * call mono_domain_get() once and we store the result in a local variable.
1129  * This function returns the variable that represents the MonoDomain*.
1130  */
1131 inline static MonoInst *
1132 mono_get_domainvar (MonoCompile *cfg)
1133 {
1134         if (!cfg->domainvar)
1135                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1136         return cfg->domainvar;
1137 }
1138
1139 /*
1140  * The got_var contains the address of the Global Offset Table when AOT 
1141  * compiling.
1142  */
1143 inline static MonoInst *
1144 mono_get_got_var (MonoCompile *cfg)
1145 {
1146 #ifdef MONO_ARCH_NEED_GOT_VAR
1147         if (!cfg->compile_aot)
1148                 return NULL;
1149         if (!cfg->got_var) {
1150                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1151         }
1152         return cfg->got_var;
1153 #else
1154         return NULL;
1155 #endif
1156 }
1157
1158 static MonoInst *
1159 mono_get_vtable_var (MonoCompile *cfg)
1160 {
1161         g_assert (cfg->generic_sharing_context);
1162
1163         if (!cfg->rgctx_var) {
1164                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1165                 /* force the var to be stack allocated */
1166                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1167         }
1168
1169         return cfg->rgctx_var;
1170 }
1171
1172 static MonoType*
1173 type_from_stack_type (MonoInst *ins) {
1174         switch (ins->type) {
1175         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1176         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1177         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1178         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1179         case STACK_MP:
1180                 return &ins->klass->this_arg;
1181         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1182         case STACK_VTYPE: return &ins->klass->byval_arg;
1183         default:
1184                 g_error ("stack type %d to montype not handled\n", ins->type);
1185         }
1186         return NULL;
1187 }
1188
1189 static G_GNUC_UNUSED int
1190 type_to_stack_type (MonoType *t)
1191 {
1192         switch (mono_type_get_underlying_type (t)->type) {
1193         case MONO_TYPE_I1:
1194         case MONO_TYPE_U1:
1195         case MONO_TYPE_BOOLEAN:
1196         case MONO_TYPE_I2:
1197         case MONO_TYPE_U2:
1198         case MONO_TYPE_CHAR:
1199         case MONO_TYPE_I4:
1200         case MONO_TYPE_U4:
1201                 return STACK_I4;
1202         case MONO_TYPE_I:
1203         case MONO_TYPE_U:
1204         case MONO_TYPE_PTR:
1205         case MONO_TYPE_FNPTR:
1206                 return STACK_PTR;
1207         case MONO_TYPE_CLASS:
1208         case MONO_TYPE_STRING:
1209         case MONO_TYPE_OBJECT:
1210         case MONO_TYPE_SZARRAY:
1211         case MONO_TYPE_ARRAY:    
1212                 return STACK_OBJ;
1213         case MONO_TYPE_I8:
1214         case MONO_TYPE_U8:
1215                 return STACK_I8;
1216         case MONO_TYPE_R4:
1217         case MONO_TYPE_R8:
1218                 return STACK_R8;
1219         case MONO_TYPE_VALUETYPE:
1220         case MONO_TYPE_TYPEDBYREF:
1221                 return STACK_VTYPE;
1222         case MONO_TYPE_GENERICINST:
1223                 if (mono_type_generic_inst_is_valuetype (t))
1224                         return STACK_VTYPE;
1225                 else
1226                         return STACK_OBJ;
1227                 break;
1228         default:
1229                 g_assert_not_reached ();
1230         }
1231
1232         return -1;
1233 }
1234
1235 static MonoClass*
1236 array_access_to_klass (int opcode)
1237 {
1238         switch (opcode) {
1239         case CEE_LDELEM_U1:
1240                 return mono_defaults.byte_class;
1241         case CEE_LDELEM_U2:
1242                 return mono_defaults.uint16_class;
1243         case CEE_LDELEM_I:
1244         case CEE_STELEM_I:
1245                 return mono_defaults.int_class;
1246         case CEE_LDELEM_I1:
1247         case CEE_STELEM_I1:
1248                 return mono_defaults.sbyte_class;
1249         case CEE_LDELEM_I2:
1250         case CEE_STELEM_I2:
1251                 return mono_defaults.int16_class;
1252         case CEE_LDELEM_I4:
1253         case CEE_STELEM_I4:
1254                 return mono_defaults.int32_class;
1255         case CEE_LDELEM_U4:
1256                 return mono_defaults.uint32_class;
1257         case CEE_LDELEM_I8:
1258         case CEE_STELEM_I8:
1259                 return mono_defaults.int64_class;
1260         case CEE_LDELEM_R4:
1261         case CEE_STELEM_R4:
1262                 return mono_defaults.single_class;
1263         case CEE_LDELEM_R8:
1264         case CEE_STELEM_R8:
1265                 return mono_defaults.double_class;
1266         case CEE_LDELEM_REF:
1267         case CEE_STELEM_REF:
1268                 return mono_defaults.object_class;
1269         default:
1270                 g_assert_not_reached ();
1271         }
1272         return NULL;
1273 }
1274
1275 /*
1276  * We try to share variables when possible
1277  */
1278 static MonoInst *
1279 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1280 {
1281         MonoInst *res;
1282         int pos, vnum;
1283
1284         /* inlining can result in deeper stacks */ 
1285         if (slot >= mono_method_get_header (cfg->method)->max_stack)
1286                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1287
1288         pos = ins->type - 1 + slot * STACK_MAX;
1289
1290         switch (ins->type) {
1291         case STACK_I4:
1292         case STACK_I8:
1293         case STACK_R8:
1294         case STACK_PTR:
1295         case STACK_MP:
1296         case STACK_OBJ:
1297                 if ((vnum = cfg->intvars [pos]))
1298                         return cfg->varinfo [vnum];
1299                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1300                 cfg->intvars [pos] = res->inst_c0;
1301                 break;
1302         default:
1303                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1304         }
1305         return res;
1306 }
1307
1308 static void
1309 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1310 {
1311         if (cfg->compile_aot) {
1312                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1313                 jump_info_token->image = image;
1314                 jump_info_token->token = token;
1315                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1316         }
1317 }
1318
1319 /*
1320  * This function is called to handle items that are left on the evaluation stack
1321  * at basic block boundaries. What happens is that we save the values to local variables
1322  * and we reload them later when first entering the target basic block (with the
1323  * handle_loaded_temps () function).
1324  * A single joint point will use the same variables (stored in the array bb->out_stack or
1325  * bb->in_stack, if the basic block is before or after the joint point).
1326  *
1327  * This function needs to be called _before_ emitting the last instruction of
1328  * the bb (i.e. before emitting a branch).
1329  * If the stack merge fails at a join point, cfg->unverifiable is set.
1330  */
1331 static void
1332 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1333 {
1334         int i, bindex;
1335         MonoBasicBlock *bb = cfg->cbb;
1336         MonoBasicBlock *outb;
1337         MonoInst *inst, **locals;
1338         gboolean found;
1339
1340         if (!count)
1341                 return;
1342         if (cfg->verbose_level > 3)
1343                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1344         if (!bb->out_scount) {
1345                 bb->out_scount = count;
1346                 //printf ("bblock %d has out:", bb->block_num);
1347                 found = FALSE;
1348                 for (i = 0; i < bb->out_count; ++i) {
1349                         outb = bb->out_bb [i];
1350                         /* exception handlers are linked, but they should not be considered for stack args */
1351                         if (outb->flags & BB_EXCEPTION_HANDLER)
1352                                 continue;
1353                         //printf (" %d", outb->block_num);
1354                         if (outb->in_stack) {
1355                                 found = TRUE;
1356                                 bb->out_stack = outb->in_stack;
1357                                 break;
1358                         }
1359                 }
1360                 //printf ("\n");
1361                 if (!found) {
1362                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1363                         for (i = 0; i < count; ++i) {
1364                                 /* 
1365                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1366                                  * stack slot and if they are of the same type.
1367                                  * This won't cause conflicts since if 'local' is used to 
1368                                  * store one of the values in the in_stack of a bblock, then
1369                                  * the same variable will be used for the same outgoing stack 
1370                                  * slot as well. 
1371                                  * This doesn't work when inlining methods, since the bblocks
1372                                  * in the inlined methods do not inherit their in_stack from
1373                                  * the bblock they are inlined to. See bug #58863 for an
1374                                  * example.
1375                                  */
1376                                 if (cfg->inlined_method)
1377                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1378                                 else
1379                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1380                         }
1381                 }
1382         }
1383
1384         for (i = 0; i < bb->out_count; ++i) {
1385                 outb = bb->out_bb [i];
1386                 /* exception handlers are linked, but they should not be considered for stack args */
1387                 if (outb->flags & BB_EXCEPTION_HANDLER)
1388                         continue;
1389                 if (outb->in_scount) {
1390                         if (outb->in_scount != bb->out_scount) {
1391                                 cfg->unverifiable = TRUE;
1392                                 return;
1393                         }
1394                         continue; /* check they are the same locals */
1395                 }
1396                 outb->in_scount = count;
1397                 outb->in_stack = bb->out_stack;
1398         }
1399
1400         locals = bb->out_stack;
1401         cfg->cbb = bb;
1402         for (i = 0; i < count; ++i) {
1403                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1404                 inst->cil_code = sp [i]->cil_code;
1405                 sp [i] = locals [i];
1406                 if (cfg->verbose_level > 3)
1407                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1408         }
1409
1410         /*
1411          * It is possible that the out bblocks already have in_stack assigned, and
1412          * the in_stacks differ. In this case, we will store to all the different 
1413          * in_stacks.
1414          */
1415
1416         found = TRUE;
1417         bindex = 0;
1418         while (found) {
1419                 /* Find a bblock which has a different in_stack */
1420                 found = FALSE;
1421                 while (bindex < bb->out_count) {
1422                         outb = bb->out_bb [bindex];
1423                         /* exception handlers are linked, but they should not be considered for stack args */
1424                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1425                                 bindex++;
1426                                 continue;
1427                         }
1428                         if (outb->in_stack != locals) {
1429                                 for (i = 0; i < count; ++i) {
1430                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1431                                         inst->cil_code = sp [i]->cil_code;
1432                                         sp [i] = locals [i];
1433                                         if (cfg->verbose_level > 3)
1434                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1435                                 }
1436                                 locals = outb->in_stack;
1437                                 found = TRUE;
1438                                 break;
1439                         }
1440                         bindex ++;
1441                 }
1442         }
1443 }
1444
1445 /* Emit code which loads interface_offsets [klass->interface_id]
1446  * The array is stored in memory before vtable.
1447 */
1448 static void
1449 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1450 {
1451         if (cfg->compile_aot) {
1452                 int ioffset_reg = alloc_preg (cfg);
1453                 int iid_reg = alloc_preg (cfg);
1454
1455                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1456                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1457                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1458         }
1459         else {
1460                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1461         }
1462 }
1463
1464 /* 
1465  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1466  * stored in "klass_reg" implements the interface "klass".
1467  */
1468 static void
1469 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1470 {
1471         int ibitmap_reg = alloc_preg (cfg);
1472         int ibitmap_byte_reg = alloc_preg (cfg);
1473
1474         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap));
1475
1476         if (cfg->compile_aot) {
1477                 int iid_reg = alloc_preg (cfg);
1478                 int shifted_iid_reg = alloc_preg (cfg);
1479                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1480                 int masked_iid_reg = alloc_preg (cfg);
1481                 int iid_one_bit_reg = alloc_preg (cfg);
1482                 int iid_bit_reg = alloc_preg (cfg);
1483                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1484                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1485                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1486                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1487                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1488                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1489                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1490                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1491         } else {
1492                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1493                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1494         }
1495 }
1496
1497 /* 
1498  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1499  * stored in "vtable_reg" implements the interface "klass".
1500  */
1501 static void
1502 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1503 {
1504         int ibitmap_reg = alloc_preg (cfg);
1505         int ibitmap_byte_reg = alloc_preg (cfg);
1506  
1507         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap));
1508
1509         if (cfg->compile_aot) {
1510                 int iid_reg = alloc_preg (cfg);
1511                 int shifted_iid_reg = alloc_preg (cfg);
1512                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1513                 int masked_iid_reg = alloc_preg (cfg);
1514                 int iid_one_bit_reg = alloc_preg (cfg);
1515                 int iid_bit_reg = alloc_preg (cfg);
1516                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1517                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, shifted_iid_reg, iid_reg, 3);
1518                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1519                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1520                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, masked_iid_reg, iid_reg, 7);
1521                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1522                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1523                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1524         } else {
1525                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1526                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1527         }
1528 }
1529
1530 /* 
1531  * Emit code which checks whenever the interface id of @klass is smaller than
1532  * than the value given by max_iid_reg.
1533 */
1534 static void
1535 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1536                                                  MonoBasicBlock *false_target)
1537 {
1538         if (cfg->compile_aot) {
1539                 int iid_reg = alloc_preg (cfg);
1540                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1541                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1542         }
1543         else
1544                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1545         if (false_target)
1546                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1547         else
1548                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1549 }
1550
1551 /* Same as above, but obtains max_iid from a vtable */
1552 static void
1553 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1554                                                                  MonoBasicBlock *false_target)
1555 {
1556         int max_iid_reg = alloc_preg (cfg);
1557                 
1558         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1559         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1560 }
1561
1562 /* Same as above, but obtains max_iid from a klass */
1563 static void
1564 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1565                                                                  MonoBasicBlock *false_target)
1566 {
1567         int max_iid_reg = alloc_preg (cfg);
1568
1569         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1570         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1571 }
1572
1573 static void 
1574 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1575 {
1576         int idepth_reg = alloc_preg (cfg);
1577         int stypes_reg = alloc_preg (cfg);
1578         int stype = alloc_preg (cfg);
1579
1580         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1581                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1582                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1583                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1584         }
1585         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1586         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1587         if (cfg->compile_aot) {
1588                 int const_reg = alloc_preg (cfg);
1589                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1590                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1591         } else {
1592                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1593         }
1594         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1595 }
1596
1597 static void 
1598 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1599 {
1600         int intf_reg = alloc_preg (cfg);
1601
1602         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1603         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1604         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1605         if (true_target)
1606                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1607         else
1608                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1609 }
1610
1611 /*
1612  * Variant of the above that takes a register to the class, not the vtable.
1613  */
1614 static void 
1615 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1616 {
1617         int intf_bit_reg = alloc_preg (cfg);
1618
1619         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1620         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1621         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1622         if (true_target)
1623                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1624         else
1625                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1626 }
1627
1628 static inline void
1629 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1630 {
1631         if (cfg->compile_aot) {
1632                 int const_reg = alloc_preg (cfg);
1633                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1634                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1635         } else {
1636                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1637         }
1638         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1639 }
1640
1641 static inline void
1642 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1643 {
1644         if (cfg->compile_aot) {
1645                 int const_reg = alloc_preg (cfg);
1646                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1647                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1648         } else {
1649                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1650         }
1651         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1652 }
1653         
1654 static void 
1655 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1656 {
1657         if (klass->rank) {
1658                 int rank_reg = alloc_preg (cfg);
1659                 int eclass_reg = alloc_preg (cfg);
1660
1661                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1662                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1663                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1664                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1665                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1666                 if (klass->cast_class == mono_defaults.object_class) {
1667                         int parent_reg = alloc_preg (cfg);
1668                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1669                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1670                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1671                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1672                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1673                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1674                 } else if (klass->cast_class == mono_defaults.enum_class) {
1675                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1676                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1677                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1678                 } else {
1679                         mini_emit_castclass (cfg, obj_reg, eclass_reg, klass->cast_class, object_is_null);
1680                 }
1681
1682                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
1683                         /* Check that the object is a vector too */
1684                         int bounds_reg = alloc_preg (cfg);
1685                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1686                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1687                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1688                 }
1689         } else {
1690                 int idepth_reg = alloc_preg (cfg);
1691                 int stypes_reg = alloc_preg (cfg);
1692                 int stype = alloc_preg (cfg);
1693
1694                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1695                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1696                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1697                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1698                 }
1699                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1700                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1701                 mini_emit_class_check (cfg, stype, klass);
1702         }
1703 }
1704
1705 static void 
1706 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1707 {
1708         int val_reg;
1709
1710         g_assert (val == 0);
1711
1712         if ((size <= 4) && (size <= align)) {
1713                 switch (size) {
1714                 case 1:
1715                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1716                         break;
1717                 case 2:
1718                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1719                         break;
1720                 case 4:
1721                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1722                         break;
1723 #if SIZEOF_VOID_P == 8
1724                 case 8:
1725                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1726 #endif
1727                 }
1728                 return;
1729         }
1730
1731         val_reg = alloc_preg (cfg);
1732
1733         if (sizeof (gpointer) == 8)
1734                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1735         else
1736                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1737
1738         if (align < 4) {
1739                 /* This could be optimized further if neccesary */
1740                 while (size >= 1) {
1741                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1742                         offset += 1;
1743                         size -= 1;
1744                 }
1745                 return;
1746         }       
1747
1748 #if !NO_UNALIGNED_ACCESS
1749         if (sizeof (gpointer) == 8) {
1750                 if (offset % 8) {
1751                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1752                         offset += 4;
1753                         size -= 4;
1754                 }
1755                 while (size >= 8) {
1756                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1757                         offset += 8;
1758                         size -= 8;
1759                 }
1760         }       
1761 #endif
1762
1763         while (size >= 4) {
1764                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1765                 offset += 4;
1766                 size -= 4;
1767         }
1768         while (size >= 2) {
1769                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1770                 offset += 2;
1771                 size -= 2;
1772         }
1773         while (size >= 1) {
1774                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1775                 offset += 1;
1776                 size -= 1;
1777         }
1778 }
1779
1780 void 
1781 mini_emit_memcpy2 (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1782 {
1783         int cur_reg;
1784
1785         if (align < 4) {
1786                 /* This could be optimized further if neccesary */
1787                 while (size >= 1) {
1788                         cur_reg = alloc_preg (cfg);
1789                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1790                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1791                         doffset += 1;
1792                         soffset += 1;
1793                         size -= 1;
1794                 }
1795         }
1796
1797 #if !NO_UNALIGNED_ACCESS
1798         if (sizeof (gpointer) == 8) {
1799                 while (size >= 8) {
1800                         cur_reg = alloc_preg (cfg);
1801                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1802                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1803                         doffset += 8;
1804                         soffset += 8;
1805                         size -= 8;
1806                 }
1807         }       
1808 #endif
1809
1810         while (size >= 4) {
1811                 cur_reg = alloc_preg (cfg);
1812                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1813                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1814                 doffset += 4;
1815                 soffset += 4;
1816                 size -= 4;
1817         }
1818         while (size >= 2) {
1819                 cur_reg = alloc_preg (cfg);
1820                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1821                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1822                 doffset += 2;
1823                 soffset += 2;
1824                 size -= 2;
1825         }
1826         while (size >= 1) {
1827                 cur_reg = alloc_preg (cfg);
1828                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1829                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1830                 doffset += 1;
1831                 soffset += 1;
1832                 size -= 1;
1833         }
1834 }
1835
1836 static void
1837 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
1838 {
1839         int vtable_reg = alloc_preg (cfg);
1840
1841         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
1842                                        
1843         if (cfg->opt & MONO_OPT_SHARED) {
1844                 int class_reg = alloc_preg (cfg);
1845                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1846                 if (cfg->compile_aot) {
1847                         int klass_reg = alloc_preg (cfg);
1848                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
1849                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
1850                 } else {
1851                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
1852                 }
1853         } else {
1854                 if (cfg->compile_aot) {
1855                         int vt_reg = alloc_preg (cfg);
1856                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, mono_class_vtable (cfg->domain, array_class));
1857                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
1858                 } else {
1859                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, mono_class_vtable (cfg->domain, array_class));
1860                 }
1861         }
1862         
1863         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
1864 }
1865
1866 static int
1867 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1868 {
1869         if (type->byref)
1870                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1871
1872 handle_enum:
1873         type = mini_get_basic_type_from_generic (gsctx, type);
1874         switch (type->type) {
1875         case MONO_TYPE_VOID:
1876                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1877         case MONO_TYPE_I1:
1878         case MONO_TYPE_U1:
1879         case MONO_TYPE_BOOLEAN:
1880         case MONO_TYPE_I2:
1881         case MONO_TYPE_U2:
1882         case MONO_TYPE_CHAR:
1883         case MONO_TYPE_I4:
1884         case MONO_TYPE_U4:
1885                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1886         case MONO_TYPE_I:
1887         case MONO_TYPE_U:
1888         case MONO_TYPE_PTR:
1889         case MONO_TYPE_FNPTR:
1890                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1891         case MONO_TYPE_CLASS:
1892         case MONO_TYPE_STRING:
1893         case MONO_TYPE_OBJECT:
1894         case MONO_TYPE_SZARRAY:
1895         case MONO_TYPE_ARRAY:    
1896                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1897         case MONO_TYPE_I8:
1898         case MONO_TYPE_U8:
1899                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1900         case MONO_TYPE_R4:
1901         case MONO_TYPE_R8:
1902                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1903         case MONO_TYPE_VALUETYPE:
1904                 if (type->data.klass->enumtype) {
1905                         type = type->data.klass->enum_basetype;
1906                         goto handle_enum;
1907                 } else
1908                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1909         case MONO_TYPE_TYPEDBYREF:
1910                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1911         case MONO_TYPE_GENERICINST:
1912                 type = &type->data.generic_class->container_class->byval_arg;
1913                 goto handle_enum;
1914         default:
1915                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1916         }
1917         return -1;
1918 }
1919
1920 /*
1921  * target_type_is_incompatible:
1922  * @cfg: MonoCompile context
1923  *
1924  * Check that the item @arg on the evaluation stack can be stored
1925  * in the target type (can be a local, or field, etc).
1926  * The cfg arg can be used to check if we need verification or just
1927  * validity checks.
1928  *
1929  * Returns: non-0 value if arg can't be stored on a target.
1930  */
1931 static int
1932 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1933 {
1934         MonoType *simple_type;
1935         MonoClass *klass;
1936
1937         if (target->byref) {
1938                 /* FIXME: check that the pointed to types match */
1939                 if (arg->type == STACK_MP)
1940                         return arg->klass != mono_class_from_mono_type (target);
1941                 if (arg->type == STACK_PTR)
1942                         return 0;
1943                 return 1;
1944         }
1945
1946         simple_type = mono_type_get_underlying_type (target);
1947         switch (simple_type->type) {
1948         case MONO_TYPE_VOID:
1949                 return 1;
1950         case MONO_TYPE_I1:
1951         case MONO_TYPE_U1:
1952         case MONO_TYPE_BOOLEAN:
1953         case MONO_TYPE_I2:
1954         case MONO_TYPE_U2:
1955         case MONO_TYPE_CHAR:
1956         case MONO_TYPE_I4:
1957         case MONO_TYPE_U4:
1958                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1959                         return 1;
1960                 return 0;
1961         case MONO_TYPE_PTR:
1962                 /* STACK_MP is needed when setting pinned locals */
1963                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1964                         return 1;
1965                 return 0;
1966         case MONO_TYPE_I:
1967         case MONO_TYPE_U:
1968         case MONO_TYPE_FNPTR:
1969                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1970                         return 1;
1971                 return 0;
1972         case MONO_TYPE_CLASS:
1973         case MONO_TYPE_STRING:
1974         case MONO_TYPE_OBJECT:
1975         case MONO_TYPE_SZARRAY:
1976         case MONO_TYPE_ARRAY:    
1977                 if (arg->type != STACK_OBJ)
1978                         return 1;
1979                 /* FIXME: check type compatibility */
1980                 return 0;
1981         case MONO_TYPE_I8:
1982         case MONO_TYPE_U8:
1983                 if (arg->type != STACK_I8)
1984                         return 1;
1985                 return 0;
1986         case MONO_TYPE_R4:
1987         case MONO_TYPE_R8:
1988                 if (arg->type != STACK_R8)
1989                         return 1;
1990                 return 0;
1991         case MONO_TYPE_VALUETYPE:
1992                 if (arg->type != STACK_VTYPE)
1993                         return 1;
1994                 klass = mono_class_from_mono_type (simple_type);
1995                 if (klass != arg->klass)
1996                         return 1;
1997                 return 0;
1998         case MONO_TYPE_TYPEDBYREF:
1999                 if (arg->type != STACK_VTYPE)
2000                         return 1;
2001                 klass = mono_class_from_mono_type (simple_type);
2002                 if (klass != arg->klass)
2003                         return 1;
2004                 return 0;
2005         case MONO_TYPE_GENERICINST:
2006                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2007                         if (arg->type != STACK_VTYPE)
2008                                 return 1;
2009                         klass = mono_class_from_mono_type (simple_type);
2010                         if (klass != arg->klass)
2011                                 return 1;
2012                         return 0;
2013                 } else {
2014                         if (arg->type != STACK_OBJ)
2015                                 return 1;
2016                         /* FIXME: check type compatibility */
2017                         return 0;
2018                 }
2019         case MONO_TYPE_VAR:
2020         case MONO_TYPE_MVAR:
2021                 /* FIXME: all the arguments must be references for now,
2022                  * later look inside cfg and see if the arg num is
2023                  * really a reference
2024                  */
2025                 g_assert (cfg->generic_sharing_context);
2026                 if (arg->type != STACK_OBJ)
2027                         return 1;
2028                 return 0;
2029         default:
2030                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2031         }
2032         return 1;
2033 }
2034
2035 /*
2036  * Prepare arguments for passing to a function call.
2037  * Return a non-zero value if the arguments can't be passed to the given
2038  * signature.
2039  * The type checks are not yet complete and some conversions may need
2040  * casts on 32 or 64 bit architectures.
2041  *
2042  * FIXME: implement this using target_type_is_incompatible ()
2043  */
2044 static int
2045 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2046 {
2047         MonoType *simple_type;
2048         int i;
2049
2050         if (sig->hasthis) {
2051                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2052                         return 1;
2053                 args++;
2054         }
2055         for (i = 0; i < sig->param_count; ++i) {
2056                 if (sig->params [i]->byref) {
2057                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2058                                 return 1;
2059                         continue;
2060                 }
2061                 simple_type = sig->params [i];
2062                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2063 handle_enum:
2064                 switch (simple_type->type) {
2065                 case MONO_TYPE_VOID:
2066                         return 1;
2067                         continue;
2068                 case MONO_TYPE_I1:
2069                 case MONO_TYPE_U1:
2070                 case MONO_TYPE_BOOLEAN:
2071                 case MONO_TYPE_I2:
2072                 case MONO_TYPE_U2:
2073                 case MONO_TYPE_CHAR:
2074                 case MONO_TYPE_I4:
2075                 case MONO_TYPE_U4:
2076                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2077                                 return 1;
2078                         continue;
2079                 case MONO_TYPE_I:
2080                 case MONO_TYPE_U:
2081                 case MONO_TYPE_PTR:
2082                 case MONO_TYPE_FNPTR:
2083                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2084                                 return 1;
2085                         continue;
2086                 case MONO_TYPE_CLASS:
2087                 case MONO_TYPE_STRING:
2088                 case MONO_TYPE_OBJECT:
2089                 case MONO_TYPE_SZARRAY:
2090                 case MONO_TYPE_ARRAY:    
2091                         if (args [i]->type != STACK_OBJ)
2092                                 return 1;
2093                         continue;
2094                 case MONO_TYPE_I8:
2095                 case MONO_TYPE_U8:
2096                         if (args [i]->type != STACK_I8)
2097                                 return 1;
2098                         continue;
2099                 case MONO_TYPE_R4:
2100                 case MONO_TYPE_R8:
2101                         if (args [i]->type != STACK_R8)
2102                                 return 1;
2103                         continue;
2104                 case MONO_TYPE_VALUETYPE:
2105                         if (simple_type->data.klass->enumtype) {
2106                                 simple_type = simple_type->data.klass->enum_basetype;
2107                                 goto handle_enum;
2108                         }
2109                         if (args [i]->type != STACK_VTYPE)
2110                                 return 1;
2111                         continue;
2112                 case MONO_TYPE_TYPEDBYREF:
2113                         if (args [i]->type != STACK_VTYPE)
2114                                 return 1;
2115                         continue;
2116                 case MONO_TYPE_GENERICINST:
2117                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2118                         goto handle_enum;
2119
2120                 default:
2121                         g_error ("unknown type 0x%02x in check_call_signature",
2122                                  simple_type->type);
2123                 }
2124         }
2125         return 0;
2126 }
2127
2128 static int
2129 callvirt_to_call (int opcode)
2130 {
2131         switch (opcode) {
2132         case OP_CALLVIRT:
2133                 return OP_CALL;
2134         case OP_VOIDCALLVIRT:
2135                 return OP_VOIDCALL;
2136         case OP_FCALLVIRT:
2137                 return OP_FCALL;
2138         case OP_VCALLVIRT:
2139                 return OP_VCALL;
2140         case OP_LCALLVIRT:
2141                 return OP_LCALL;
2142         default:
2143                 g_assert_not_reached ();
2144         }
2145
2146         return -1;
2147 }
2148
2149 static int
2150 callvirt_to_call_membase (int opcode)
2151 {
2152         switch (opcode) {
2153         case OP_CALLVIRT:
2154                 return OP_CALL_MEMBASE;
2155         case OP_VOIDCALLVIRT:
2156                 return OP_VOIDCALL_MEMBASE;
2157         case OP_FCALLVIRT:
2158                 return OP_FCALL_MEMBASE;
2159         case OP_LCALLVIRT:
2160                 return OP_LCALL_MEMBASE;
2161         case OP_VCALLVIRT:
2162                 return OP_VCALL_MEMBASE;
2163         default:
2164                 g_assert_not_reached ();
2165         }
2166
2167         return -1;
2168 }
2169
2170 #ifdef MONO_ARCH_HAVE_IMT
2171 static void
2172 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
2173 {
2174 #ifdef MONO_ARCH_IMT_REG
2175         int method_reg = alloc_preg (cfg);
2176
2177         if (cfg->compile_aot) {
2178                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
2179         } else if (imt_arg) {
2180                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2181         } else {
2182                 MonoInst *ins;
2183                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2184                 ins->inst_p0 = call->method;
2185                 ins->dreg = method_reg;
2186                 MONO_ADD_INS (cfg->cbb, ins);
2187         }
2188
2189         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2190 #else
2191         mono_arch_emit_imt_argument (cfg, call);
2192 #endif
2193 }
2194 #endif
2195
2196 inline static MonoInst*
2197 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args);
2198
2199 inline static MonoCallInst *
2200 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2201                      MonoInst **args, int calli, int virtual)
2202 {
2203         MonoCallInst *call;
2204 #ifdef MONO_ARCH_SOFT_FLOAT
2205         int i;
2206 #endif
2207
2208         MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2209
2210         call->args = args;
2211         call->signature = sig;
2212
2213         type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
2214
2215         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2216                 MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
2217                 MonoInst *loada;
2218
2219                 temp->backend.is_pinvoke = sig->pinvoke;
2220
2221                 /*
2222                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2223                  * address of return value to increase optimization opportunities.
2224                  * Before vtype decomposition, the dreg of the call ins itself represents the
2225                  * fact the call modifies the return value. After decomposition, the call will
2226                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2227                  * will be transformed into an LDADDR.
2228                  */
2229                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2230                 loada->dreg = alloc_preg (cfg);
2231                 loada->inst_p0 = temp;
2232                 /* We reference the call too since call->dreg could change during optimization */
2233                 loada->inst_p1 = call;
2234                 MONO_ADD_INS (cfg->cbb, loada);
2235
2236                 call->inst.dreg = temp->dreg;
2237
2238                 call->vret_var = loada;
2239         } else if (!MONO_TYPE_IS_VOID (sig->ret))
2240                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2241
2242 #ifdef MONO_ARCH_SOFT_FLOAT
2243         /* 
2244          * If the call has a float argument, we would need to do an r8->r4 conversion using 
2245          * an icall, but that cannot be done during the call sequence since it would clobber
2246          * the call registers + the stack. So we do it before emitting the call.
2247          */
2248         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2249                 MonoType *t;
2250                 MonoInst *in = call->args [i];
2251
2252                 if (i >= sig->hasthis)
2253                         t = sig->params [i - sig->hasthis];
2254                 else
2255                         t = &mono_defaults.int_class->byval_arg;
2256                 t = mono_type_get_underlying_type (t);
2257
2258                 if (!t->byref && t->type == MONO_TYPE_R4) {
2259                         MonoInst *iargs [1];
2260                         MonoInst *conv;
2261
2262                         iargs [0] = in;
2263                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2264
2265                         /* The result will be in an int vreg */
2266                         call->args [i] = conv;
2267                 }
2268         }
2269 #endif
2270
2271         mono_arch_emit_call (cfg, call);
2272
2273         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2274         cfg->flags |= MONO_CFG_HAS_CALLS;
2275         
2276         return call;
2277 }
2278
2279 inline static MonoInst*
2280 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
2281 {
2282         MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE);
2283
2284         call->inst.sreg1 = addr->dreg;
2285
2286         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2287
2288         return (MonoInst*)call;
2289 }
2290
2291 inline static MonoInst*
2292 mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
2293 {
2294 #ifdef MONO_ARCH_RGCTX_REG
2295         MonoCallInst *call;
2296         int rgctx_reg = mono_alloc_preg (cfg);
2297
2298         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2299         call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
2300         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2301         return (MonoInst*)call;
2302 #else
2303         g_assert_not_reached ();
2304         return NULL;
2305 #endif
2306 }
2307
2308 static MonoInst*
2309 mono_emit_imt_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2310                                                    MonoInst **args, MonoInst *this, MonoInst *imt_arg)
2311 {
2312         gboolean virtual = this != NULL;
2313         gboolean enable_for_aot = TRUE;
2314         MonoCallInst *call;
2315
2316         if (method->string_ctor) {
2317                 /* Create the real signature */
2318                 /* FIXME: Cache these */
2319                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup (sig);
2320                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2321
2322                 sig = ctor_sig;
2323         }
2324
2325         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual);
2326
2327         if (this && sig->hasthis && 
2328             (method->klass->marshalbyref || method->klass == mono_defaults.object_class) && 
2329             !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this)) {
2330                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2331         } else {
2332                 call->method = method;
2333         }
2334         call->inst.flags |= MONO_INST_HAS_METHOD;
2335         call->inst.inst_left = this;
2336
2337         if (virtual) {
2338                 int vtable_reg, slot_reg, this_reg;
2339
2340                 this_reg = this->dreg;
2341
2342                 if ((!cfg->compile_aot || enable_for_aot) && 
2343                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2344                          ((method->flags & METHOD_ATTRIBUTE_FINAL) && 
2345                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK))) {
2346                         /* 
2347                          * the method is not virtual, we just need to ensure this is not null
2348                          * and then we can call the method directly.
2349                          */
2350                         if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
2351                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2352                         }
2353
2354                         if (!method->string_ctor) {
2355                                 cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
2356                                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
2357                                 MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
2358                         }
2359
2360                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2361
2362                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2363
2364                         return (MonoInst*)call;
2365                 }
2366
2367 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
2368                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2369                         /* Make a call to delegate->invoke_impl */
2370                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2371                         call->inst.inst_basereg = this_reg;
2372                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2373                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2374
2375                         return (MonoInst*)call;
2376                 }
2377 #endif
2378
2379                 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
2380                         ((method->flags &  METHOD_ATTRIBUTE_FINAL) ||
2381                          (method->klass && method->klass->flags & TYPE_ATTRIBUTE_SEALED))) {
2382                         /*
2383                          * the method is virtual, but we can statically dispatch since either
2384                          * it's class or the method itself are sealed.
2385                          * But first we need to ensure it's not a null reference.
2386                          */
2387                         cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
2388                         MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, this_reg);
2389                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, this_reg);
2390
2391                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2392                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2393
2394                         return (MonoInst*)call;
2395                 }
2396
2397                 call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2398
2399                 /* Initialize method->slot */
2400                 mono_class_setup_vtable (method->klass);
2401
2402                 vtable_reg = alloc_preg (cfg);
2403                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2404                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2405                         slot_reg = -1;
2406 #ifdef MONO_ARCH_HAVE_IMT
2407                         if (mono_use_imt) {
2408                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2409                                 emit_imt_argument (cfg, call, imt_arg);
2410                                 slot_reg = vtable_reg;
2411                                 call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2412                         }
2413 #endif
2414                         if (slot_reg == -1) {
2415                                 slot_reg = alloc_preg (cfg);
2416                                 mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2417                                 call->inst.inst_offset = method->slot * SIZEOF_VOID_P;
2418                         }
2419                 } else {
2420                         slot_reg = vtable_reg;
2421                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) + (method->slot * SIZEOF_VOID_P);
2422                 }
2423
2424                 call->inst.sreg1 = slot_reg;
2425                 call->virtual = TRUE;
2426         }
2427
2428         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2429
2430         return (MonoInst*)call;
2431 }
2432
2433 static inline MonoInst*
2434 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2435                                            MonoInst **args, MonoInst *this)
2436 {
2437         return mono_emit_imt_method_call (cfg, method, sig, args, this, NULL);
2438 }
2439
2440 MonoInst*
2441 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2442                                            MonoInst **args)
2443 {
2444         MonoCallInst *call;
2445
2446         g_assert (sig);
2447
2448         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE);
2449         call->fptr = func;
2450
2451         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2452
2453         return (MonoInst*)call;
2454 }
2455
2456 inline static MonoInst*
2457 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2458 {
2459         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2460
2461         g_assert (info);
2462
2463         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2464 }
2465
2466 static MonoMethod*
2467 get_memcpy_method (void)
2468 {
2469         static MonoMethod *memcpy_method = NULL;
2470         if (!memcpy_method) {
2471                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2472                 if (!memcpy_method)
2473                         g_error ("Old corlib found. Install a new one");
2474         }
2475         return memcpy_method;
2476 }
2477
2478 /*
2479  * Emit code to copy a valuetype of type @klass whose address is stored in
2480  * @src->dreg to memory whose address is stored at @dest->dreg.
2481  */
2482 void
2483 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
2484 {
2485         MonoInst *iargs [3];
2486         int n;
2487         guint32 align = 0;
2488         MonoMethod *memcpy_method;
2489
2490         g_assert (klass);
2491         /*
2492          * This check breaks with spilled vars... need to handle it during verification anyway.
2493          * g_assert (klass && klass == src->klass && klass == dest->klass);
2494          */
2495
2496         if (native)
2497                 n = mono_class_native_size (klass, &align);
2498         else
2499                 n = mono_class_value_size (klass, &align);
2500
2501         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
2502                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
2503                 mini_emit_memcpy2 (cfg, dest->dreg, 0, src->dreg, 0, n, align);
2504         } else {
2505                 iargs [0] = dest;
2506                 iargs [1] = src;
2507                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2508                 
2509                 memcpy_method = get_memcpy_method ();
2510                 mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
2511         }
2512 }
2513
2514 static MonoMethod*
2515 get_memset_method (void)
2516 {
2517         static MonoMethod *memset_method = NULL;
2518         if (!memset_method) {
2519                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2520                 if (!memset_method)
2521                         g_error ("Old corlib found. Install a new one");
2522         }
2523         return memset_method;
2524 }
2525
2526 void
2527 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
2528 {
2529         MonoInst *iargs [3];
2530         int n;
2531         guint32 align;
2532         MonoMethod *memset_method;
2533
2534         /* FIXME: Optimize this for the case when dest is an LDADDR */
2535
2536         mono_class_init (klass);
2537         n = mono_class_value_size (klass, &align);
2538
2539         if (n <= sizeof (gpointer) * 5) {
2540                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
2541         }
2542         else {
2543                 memset_method = get_memset_method ();
2544                 iargs [0] = dest;
2545                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
2546                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2547                 mono_emit_method_call (cfg, memset_method, memset_method->signature, iargs, NULL);
2548         }
2549 }
2550
2551 static MonoInst*
2552 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used, MonoInst *this)
2553 {
2554         g_assert (!method->klass->valuetype);
2555
2556         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
2557                 MonoInst *mrgctx_loc, *mrgctx_var;
2558
2559                 g_assert (!this);
2560                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
2561
2562                 mrgctx_loc = mono_get_vtable_var (cfg);
2563                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
2564
2565                 return mrgctx_var;
2566         } else if (method->flags & METHOD_ATTRIBUTE_STATIC) {
2567                 MonoInst *vtable_loc, *vtable_var;
2568
2569                 g_assert (!this);
2570
2571                 vtable_loc = mono_get_vtable_var (cfg);
2572                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
2573
2574                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
2575                         MonoInst *mrgctx_var = vtable_var;
2576                         int vtable_reg;
2577
2578                         vtable_reg = alloc_preg (cfg);
2579                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
2580                         vtable_var->type = STACK_PTR;
2581                 }
2582
2583                 return vtable_var;
2584         } else {
2585                 MonoInst *ins;
2586                 int vtable_reg, res_reg;
2587         
2588                 vtable_reg = alloc_preg (cfg);
2589                 res_reg = alloc_preg (cfg);
2590                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
2591                 return ins;
2592         }
2593 }
2594
2595 #define EMIT_GET_RGCTX(rgctx, context_used) do {                                \
2596                 MonoInst *this = NULL;                                  \
2597                 GENERIC_SHARING_FAILURE_IF_VALUETYPE_METHOD(*ip);       \
2598                 if (!(method->flags & METHOD_ATTRIBUTE_STATIC) && !((context_used) & MONO_GENERIC_CONTEXT_USED_METHOD)) \
2599                         EMIT_NEW_ARGLOAD (cfg, this, 0);                        \
2600                 (rgctx) = emit_get_rgctx (cfg, method, (context_used), this); \
2601         } while (0)
2602
2603 static MonoInst*
2604 emit_get_rgctx_other_table_ptr (MonoCompile *cfg, MonoInst *rgc_ptr, int slot)
2605 {
2606         MonoMethodSignature *sig = helper_sig_rgctx_lazy_fetch_trampoline;
2607         guint8 *tramp = mini_create_rgctx_lazy_fetch_trampoline (slot);
2608
2609         return mono_emit_native_call (cfg, tramp, sig, &rgc_ptr);
2610 }
2611
2612 static MonoInst*
2613 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
2614                                           MonoInst *rgctx, MonoClass *klass, int rgctx_type)
2615 {
2616         guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
2617                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, &klass->byval_arg, rgctx_type, cfg->generic_context);
2618
2619         return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
2620 }
2621
2622 static MonoInst*
2623 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
2624                                            MonoInst *rgctx, MonoMethod *cmethod, int rgctx_type)
2625 {
2626         guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
2627                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, cmethod, rgctx_type, cfg->generic_context);
2628
2629         return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
2630 }
2631
2632 static MonoInst*
2633 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
2634                                           MonoInst *rgctx, MonoClassField *field, int rgctx_type)
2635 {
2636         guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
2637                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, field, rgctx_type, cfg->generic_context);
2638
2639         return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
2640 }
2641
2642 static MonoInst*
2643 emit_get_rgctx_method_rgctx (MonoCompile *cfg, int context_used,
2644                                                          MonoInst *rgctx, MonoMethod *rgctx_method)
2645 {
2646         guint32 slot = mono_method_lookup_or_register_other_info (cfg->current_method,
2647                 context_used & MONO_GENERIC_CONTEXT_USED_METHOD, rgctx_method,
2648                 MONO_RGCTX_INFO_METHOD_RGCTX, cfg->generic_context);
2649
2650         return emit_get_rgctx_other_table_ptr (cfg, rgctx, slot);
2651 }
2652
2653 /**
2654  * Handles unbox of a Nullable<T>. If a rgctx is passed, then shared generic code
2655  * is generated.
2656  */
2657 static MonoInst*
2658 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used, MonoInst *rgctx)
2659 {
2660         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
2661         // Can't encode method ref
2662         cfg->disable_aot = TRUE;
2663
2664         if (rgctx) {
2665                 MonoInst *addr = emit_get_rgctx_method (cfg, context_used, rgctx, method,
2666                                                                                                 MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
2667
2668                 return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
2669         } else {
2670                 return mono_emit_method_call (cfg, method, mono_method_signature (method), &val, NULL);
2671         }
2672 }
2673
2674 static MonoInst*
2675 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used, MonoInst *rgctx)
2676 {
2677         MonoInst *add;
2678         int obj_reg;
2679         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
2680         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
2681         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
2682         int rank_reg = alloc_dreg (cfg ,STACK_I4);
2683
2684         obj_reg = sp [0]->dreg;
2685         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2686         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
2687
2688         /* FIXME: generics */
2689         g_assert (klass->rank == 0);
2690                         
2691         // Check rank == 0
2692         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
2693         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
2694
2695         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2696         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
2697
2698         if (context_used) {
2699                 MonoInst *element_class;
2700
2701                 /* This assertion is from the unboxcast insn */
2702                 g_assert (klass->rank == 0);
2703
2704                 element_class = emit_get_rgctx_klass (cfg, context_used, rgctx,
2705                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
2706
2707                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
2708                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
2709         } else {
2710                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
2711         }
2712
2713         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_PTR), obj_reg, sizeof (MonoObject));
2714         MONO_ADD_INS (cfg->cbb, add);
2715         add->type = STACK_MP;
2716         add->klass = klass;
2717
2718         return add;
2719 }
2720
2721 static MonoInst*
2722 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box)
2723 {
2724         MonoInst *iargs [2];
2725         void *alloc_ftn;
2726
2727         if (cfg->opt & MONO_OPT_SHARED) {
2728                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
2729                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
2730
2731                 alloc_ftn = mono_object_new;
2732         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib) {
2733                 /* This happens often in argument checking code, eg. throw new FooException... */
2734                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
2735                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
2736                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
2737         } else {
2738                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2739                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
2740                 gboolean pass_lw;
2741
2742                 if (managed_alloc) {
2743                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
2744                         return mono_emit_method_call (cfg, managed_alloc, mono_method_signature (managed_alloc), iargs, NULL);
2745                 }
2746                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
2747                 if (pass_lw) {
2748                         guint32 lw = vtable->klass->instance_size;
2749                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
2750                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
2751                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
2752                 }
2753                 else {
2754                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
2755                 }
2756         }
2757
2758         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
2759 }
2760
2761 static MonoInst*
2762 handle_alloc_from_inst (MonoCompile *cfg, MonoClass *klass, MonoInst *data_inst,
2763                                                 gboolean for_box)
2764 {
2765         MonoInst *iargs [2];
2766         MonoMethod *managed_alloc = NULL;
2767         void *alloc_ftn;
2768
2769         /*
2770           FIXME: we cannot get managed_alloc here because we can't get
2771           the class's vtable (because it's not a closed class)
2772
2773         MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2774         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
2775         */
2776
2777         if (cfg->opt & MONO_OPT_SHARED) {
2778                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
2779                 iargs [1] = data_inst;
2780                 alloc_ftn = mono_object_new;
2781         } else {
2782                 g_assert (!cfg->compile_aot);
2783
2784                 if (managed_alloc) {
2785                         iargs [0] = data_inst;
2786                         return mono_emit_method_call (cfg, managed_alloc,
2787                                                                                   mono_method_signature (managed_alloc), iargs, NULL);
2788                 }
2789
2790                 iargs [0] = data_inst;
2791                 alloc_ftn = mono_object_new_specific;
2792         }
2793
2794         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
2795 }
2796         
2797 static MonoInst*
2798 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass)
2799 {
2800         MonoInst *alloc, *ins;
2801
2802         if (mono_class_is_nullable (klass)) {
2803                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
2804                 // Can't encode method ref
2805                 cfg->disable_aot = TRUE;
2806                 return mono_emit_method_call (cfg, method, mono_method_signature (method), &val, NULL);
2807         }
2808
2809         alloc = handle_alloc (cfg, klass, TRUE);
2810
2811         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
2812
2813         return alloc;
2814 }
2815
2816 static MonoInst *
2817 handle_box_from_inst (MonoCompile *cfg, MonoInst *val, MonoClass *klass, MonoInst *data_inst)
2818 {
2819         MonoInst *alloc, *ins;
2820
2821         g_assert (!mono_class_is_nullable (klass));
2822
2823         alloc = handle_alloc_from_inst (cfg, klass, data_inst, TRUE);
2824
2825         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
2826
2827         return alloc;
2828 }
2829
2830 static MonoInst*
2831 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
2832 {
2833         MonoBasicBlock *is_null_bb;
2834         int obj_reg = src->dreg;
2835         int vtable_reg = alloc_preg (cfg);
2836
2837         NEW_BBLOCK (cfg, is_null_bb);
2838
2839         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
2840         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
2841
2842         if (mini_get_debug_options ()->better_cast_details) {
2843                 int to_klass_reg = alloc_preg (cfg);
2844                 int klass_reg = alloc_preg (cfg);
2845                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
2846
2847                 if (!tls_get) {
2848                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
2849                         exit (1);
2850                 }
2851
2852                 MONO_ADD_INS (cfg->cbb, tls_get);
2853                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2854                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2855
2856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
2857                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
2858                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
2859         }
2860
2861         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2862                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2863                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
2864         } else {
2865                 int klass_reg = alloc_preg (cfg);
2866
2867                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2868
2869                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
2870                         /* the remoting code is broken, access the class for now */
2871                         if (0) {
2872                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
2873                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
2874                         } else {
2875                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2876                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
2877                         }
2878                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
2879                 } else {
2880                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2881                         mini_emit_castclass (cfg, obj_reg, klass_reg, klass, is_null_bb);
2882                 }
2883         }
2884
2885         MONO_START_BB (cfg, is_null_bb);
2886
2887         /* Reset the variables holding the cast details */
2888         if (mini_get_debug_options ()->better_cast_details) {
2889                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
2890
2891                 MONO_ADD_INS (cfg->cbb, tls_get);
2892                 /* It is enough to reset the from field */
2893                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
2894         }
2895
2896         return src;
2897 }
2898
2899 static MonoInst*
2900 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
2901 {
2902         MonoInst *ins;
2903         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
2904         int obj_reg = src->dreg;
2905         int vtable_reg = alloc_preg (cfg);
2906         int res_reg = alloc_preg (cfg);
2907
2908         NEW_BBLOCK (cfg, is_null_bb);
2909         NEW_BBLOCK (cfg, false_bb);
2910         NEW_BBLOCK (cfg, end_bb);
2911
2912         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
2913         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
2914
2915         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2916                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2917                 /* the is_null_bb target simply copies the input register to the output */
2918                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
2919         } else {
2920                 int klass_reg = alloc_preg (cfg);
2921
2922                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2923
2924                 if (klass->rank) {
2925                         int rank_reg = alloc_preg (cfg);
2926                         int eclass_reg = alloc_preg (cfg);
2927
2928                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
2929                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
2930                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
2931                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2932                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
2933                         if (klass->cast_class == mono_defaults.object_class) {
2934                                 int parent_reg = alloc_preg (cfg);
2935                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
2936                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
2937                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
2938                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
2939                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
2940                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
2941                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
2942                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
2943                         } else if (klass->cast_class == mono_defaults.enum_class) {
2944                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
2945                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
2946                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
2947                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
2948                         } else {
2949                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
2950                                         /* Check that the object is a vector too */
2951                                         int bounds_reg = alloc_preg (cfg);
2952                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
2953                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
2954                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
2955                                 }
2956
2957                                 /* the is_null_bb target simply copies the input register to the output */
2958                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
2959                         }
2960                 } else if (mono_class_is_nullable (klass)) {
2961                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2962                         /* the is_null_bb target simply copies the input register to the output */
2963                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
2964                 } else {
2965                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
2966                                 /* the remoting code is broken, access the class for now */
2967                                 if (0) {
2968                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
2969                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
2970                                 } else {
2971                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2972                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
2973                                 }
2974                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
2975                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
2976                         } else {
2977                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
2978                                 /* the is_null_bb target simply copies the input register to the output */
2979                                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, is_null_bb);
2980                         }
2981                 }
2982         }
2983
2984         MONO_START_BB (cfg, false_bb);
2985
2986         MONO_EMIT_NEW_ICONST (cfg, res_reg, 0);
2987         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
2988
2989         MONO_START_BB (cfg, is_null_bb);
2990
2991         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
2992         ins->type = STACK_OBJ;
2993         ins->klass = klass;
2994
2995         MONO_START_BB (cfg, end_bb);
2996
2997         return ins;
2998 }
2999
3000 static MonoInst*
3001 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3002 {
3003         /* This opcode takes as input an object reference and a class, and returns:
3004         0) if the object is an instance of the class,
3005         1) if the object is not instance of the class,
3006         2) if the object is a proxy whose type cannot be determined */
3007
3008         MonoInst *ins;
3009         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
3010         int obj_reg = src->dreg;
3011         int dreg = alloc_ireg (cfg);
3012         int tmp_reg;
3013         int klass_reg = alloc_preg (cfg);
3014
3015         NEW_BBLOCK (cfg, true_bb);
3016         NEW_BBLOCK (cfg, false_bb);
3017         NEW_BBLOCK (cfg, false2_bb);
3018         NEW_BBLOCK (cfg, end_bb);
3019         NEW_BBLOCK (cfg, no_proxy_bb);
3020
3021         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3022         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
3023
3024         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3025                 NEW_BBLOCK (cfg, interface_fail_bb);
3026
3027                 tmp_reg = alloc_preg (cfg);
3028                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3029                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
3030                 MONO_START_BB (cfg, interface_fail_bb);
3031                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3032                 
3033                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
3034
3035                 tmp_reg = alloc_preg (cfg);
3036                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3037                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3038                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
3039         } else {
3040                 tmp_reg = alloc_preg (cfg);
3041                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3042                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3043
3044                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3045                 tmp_reg = alloc_preg (cfg);
3046                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3047                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3048
3049                 tmp_reg = alloc_preg (cfg);             
3050                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3051                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3052                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3053                 
3054                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
3055                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
3056
3057                 MONO_START_BB (cfg, no_proxy_bb);
3058
3059                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
3060         }
3061
3062         MONO_START_BB (cfg, false_bb);
3063
3064         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3065         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3066
3067         MONO_START_BB (cfg, false2_bb);
3068
3069         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
3070         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3071
3072         MONO_START_BB (cfg, true_bb);
3073
3074         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3075
3076         MONO_START_BB (cfg, end_bb);
3077
3078         /* FIXME: */
3079         MONO_INST_NEW (cfg, ins, OP_ICONST);
3080         ins->dreg = dreg;
3081         ins->type = STACK_I4;
3082
3083         return ins;
3084 }
3085
3086 static MonoInst*
3087 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3088 {
3089         /* This opcode takes as input an object reference and a class, and returns:
3090         0) if the object is an instance of the class,
3091         1) if the object is a proxy whose type cannot be determined
3092         an InvalidCastException exception is thrown otherwhise*/
3093         
3094         MonoInst *ins;
3095         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
3096         int obj_reg = src->dreg;
3097         int dreg = alloc_ireg (cfg);
3098         int tmp_reg = alloc_preg (cfg);
3099         int klass_reg = alloc_preg (cfg);
3100
3101         NEW_BBLOCK (cfg, end_bb);
3102         NEW_BBLOCK (cfg, ok_result_bb);
3103
3104         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3105         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
3106
3107         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3108                 NEW_BBLOCK (cfg, interface_fail_bb);
3109         
3110                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3111                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
3112                 MONO_START_BB (cfg, interface_fail_bb);
3113                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3114
3115                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
3116
3117                 tmp_reg = alloc_preg (cfg);             
3118                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3119                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3120                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
3121                 
3122                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3123                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3124                 
3125         } else {
3126                 NEW_BBLOCK (cfg, no_proxy_bb);
3127
3128                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3129                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3130                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3131
3132                 tmp_reg = alloc_preg (cfg);
3133                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3134                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3135
3136                 tmp_reg = alloc_preg (cfg);
3137                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3138                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3139                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3140
3141                 NEW_BBLOCK (cfg, fail_1_bb);
3142                 
3143                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
3144
3145                 MONO_START_BB (cfg, fail_1_bb);
3146
3147                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3148                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3149
3150                 MONO_START_BB (cfg, no_proxy_bb);
3151
3152                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
3153         }
3154
3155         MONO_START_BB (cfg, ok_result_bb);
3156
3157         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3158
3159         MONO_START_BB (cfg, end_bb);
3160
3161         /* FIXME: */
3162         MONO_INST_NEW (cfg, ins, OP_ICONST);
3163         ins->dreg = dreg;
3164         ins->type = STACK_I4;
3165
3166         return ins;
3167 }
3168
3169 static G_GNUC_UNUSED MonoInst*
3170 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method)
3171 {
3172         gpointer *trampoline;
3173         MonoInst *obj, *method_ins, *tramp_ins;
3174
3175         obj = handle_alloc (cfg, klass, FALSE);
3176
3177         /* Inline the contents of mono_delegate_ctor */
3178
3179         /* Set target field */
3180         /* Optimize away setting of NULL target */
3181         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0))
3182                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
3183
3184         /* Set method field */
3185         EMIT_NEW_METHODCONST (cfg, method_ins, method);
3186         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
3187
3188         /* Set invoke_impl field */
3189         trampoline = mono_create_delegate_trampoline (klass);
3190         EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_ABS, trampoline);
3191         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
3192
3193         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3194
3195         return obj;
3196 }
3197
3198 static MonoInst*
3199 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
3200 {
3201         MonoJitICallInfo *info;
3202
3203         /* Need to register the icall so it gets an icall wrapper */
3204         info = mono_get_array_new_va_icall (rank);
3205
3206         cfg->flags |= MONO_CFG_HAS_VARARGS;
3207
3208         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3209         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
3210 }
3211
3212 static void
3213 mono_emit_load_got_addr (MonoCompile *cfg)
3214 {
3215         MonoInst *getaddr, *dummy_use;
3216
3217         if (!cfg->got_var || cfg->got_var_allocated)
3218                 return;
3219
3220         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
3221         getaddr->dreg = cfg->got_var->dreg;
3222
3223         /* Add it to the start of the first bblock */
3224         if (cfg->bb_entry->code) {
3225                 getaddr->next = cfg->bb_entry->code;
3226                 cfg->bb_entry->code = getaddr;
3227         }
3228         else
3229                 MONO_ADD_INS (cfg->bb_entry, getaddr);
3230
3231         cfg->got_var_allocated = TRUE;
3232
3233         /* 
3234          * Add a dummy use to keep the got_var alive, since real uses might
3235          * only be generated by the back ends.
3236          * Add it to end_bblock, so the variable's lifetime covers the whole
3237          * method.
3238          * It would be better to make the usage of the got var explicit in all
3239          * cases when the backend needs it (i.e. calls, throw etc.), so this
3240          * wouldn't be needed.
3241          */
3242         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
3243         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3244 }
3245
3246 #define CODE_IS_STLOC(ip) (((ip) [0] >= CEE_STLOC_0 && (ip) [0] <= CEE_STLOC_3) || ((ip) [0] == CEE_STLOC_S))
3247
3248 static gboolean
3249 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3250 {
3251         MonoMethodHeader *header = mono_method_get_header (method);
3252         MonoVTable *vtable;
3253 #ifdef MONO_ARCH_SOFT_FLOAT
3254         MonoMethodSignature *sig = mono_method_signature (method);
3255         int i;
3256 #endif
3257
3258         if (cfg->generic_sharing_context)
3259                 return FALSE;
3260
3261 #ifdef MONO_ARCH_HAVE_LMF_OPS
3262         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3263                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3264             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3265                 return TRUE;
3266 #endif
3267
3268         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
3269             (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3270             (method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3271             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3272             (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
3273             (method->klass->marshalbyref) ||
3274             !header || header->num_clauses)
3275                 return FALSE;
3276
3277         /* also consider num_locals? */
3278         /* Do the size check early to avoid creating vtables */
3279         if (getenv ("MONO_INLINELIMIT")) {
3280                 if (header->code_size >= atoi (getenv ("MONO_INLINELIMIT"))) {
3281                         return FALSE;
3282                 }
3283         } else if (header->code_size >= INLINE_LENGTH_LIMIT)
3284                 return FALSE;
3285
3286         /*
3287          * if we can initialize the class of the method right away, we do,
3288          * otherwise we don't allow inlining if the class needs initialization,
3289          * since it would mean inserting a call to mono_runtime_class_init()
3290          * inside the inlined code
3291          */
3292         if (!(cfg->opt & MONO_OPT_SHARED)) {
3293                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3294                         if (cfg->run_cctors && method->klass->has_cctor) {
3295                                 if (!method->klass->runtime_info)
3296                                         /* No vtable created yet */
3297                                         return FALSE;
3298                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3299                                 if (!vtable)
3300                                         return FALSE;
3301                                 /* This makes so that inline cannot trigger */
3302                                 /* .cctors: too many apps depend on them */
3303                                 /* running with a specific order... */
3304                                 if (! vtable->initialized)
3305                                         return FALSE;
3306                                 mono_runtime_class_init (vtable);
3307                         }
3308                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3309                         if (!method->klass->runtime_info)
3310                                 /* No vtable created yet */
3311                                 return FALSE;
3312                         vtable = mono_class_vtable (cfg->domain, method->klass);
3313                         if (!vtable)
3314                                 return FALSE;
3315                         if (!vtable->initialized)
3316                                 return FALSE;
3317                 }
3318         } else {
3319                 /* 
3320                  * If we're compiling for shared code
3321                  * the cctor will need to be run at aot method load time, for example,
3322                  * or at the end of the compilation of the inlining method.
3323                  */
3324                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3325                         return FALSE;
3326         }
3327
3328         /*
3329          * CAS - do not inline methods with declarative security
3330          * Note: this has to be before any possible return TRUE;
3331          */
3332         if (mono_method_has_declsec (method))
3333                 return FALSE;
3334
3335 #ifdef MONO_ARCH_SOFT_FLOAT
3336         /* FIXME: */
3337         if (sig->ret && sig->ret->type == MONO_TYPE_R4)
3338                 return FALSE;
3339         for (i = 0; i < sig->param_count; ++i)
3340                 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
3341                         return FALSE;
3342 #endif
3343
3344         return TRUE;
3345 }
3346
3347 static gboolean
3348 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3349 {
3350         if (vtable->initialized && !cfg->compile_aot)
3351                 return FALSE;
3352
3353         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3354                 return FALSE;
3355
3356         if (!mono_class_needs_cctor_run (vtable->klass, method))
3357                 return FALSE;
3358
3359         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
3360                 /* The initialization is already done before the method is called */
3361                 return FALSE;
3362
3363         return TRUE;
3364 }
3365
3366 static MonoInst*
3367 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index)
3368 {
3369         MonoInst *ins;
3370         guint32 size;
3371         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
3372
3373         mono_class_init (klass);
3374         size = mono_class_array_element_size (klass);
3375
3376         mult_reg = alloc_preg (cfg);
3377         array_reg = arr->dreg;
3378         index_reg = index->dreg;
3379
3380 #if SIZEOF_VOID_P == 8
3381         /* The array reg is 64 bits but the index reg is only 32 */
3382         index2_reg = alloc_preg (cfg);
3383         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
3384 #else
3385         index2_reg = index_reg;
3386 #endif
3387
3388         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
3389
3390 #if defined(__i386__) || defined(__x86_64__)
3391         if (size == 1 || size == 2 || size == 4 || size == 8) {
3392                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
3393
3394                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
3395                 ins->type = STACK_PTR;
3396
3397                 return ins;
3398         }
3399 #endif          
3400
3401         add_reg = alloc_preg (cfg);
3402
3403         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
3404         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
3405         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
3406         ins->type = STACK_PTR;
3407         MONO_ADD_INS (cfg->cbb, ins);
3408
3409         return ins;
3410 }
3411
3412 #ifndef MONO_ARCH_EMULATE_MUL_DIV
3413 static MonoInst*
3414 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
3415 {
3416         int bounds_reg = alloc_preg (cfg);
3417         int add_reg = alloc_preg (cfg);
3418         int mult_reg = alloc_preg (cfg);
3419         int mult2_reg = alloc_preg (cfg);
3420         int low1_reg = alloc_preg (cfg);
3421         int low2_reg = alloc_preg (cfg);
3422         int high1_reg = alloc_preg (cfg);
3423         int high2_reg = alloc_preg (cfg);
3424         int realidx1_reg = alloc_preg (cfg);
3425         int realidx2_reg = alloc_preg (cfg);
3426         int sum_reg = alloc_preg (cfg);
3427         int index1, index2;
3428         MonoInst *ins;
3429         guint32 size;
3430
3431         mono_class_init (klass);
3432         size = mono_class_array_element_size (klass);
3433
3434         index1 = index_ins1->dreg;
3435         index2 = index_ins2->dreg;
3436
3437         /* range checking */
3438         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
3439                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
3440
3441         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
3442                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3443         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
3444         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
3445                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
3446         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
3447         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
3448
3449         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
3450                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
3451         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
3452         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
3453                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
3454         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
3455         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
3456
3457         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
3458         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
3459         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
3460         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
3461         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
3462
3463         ins->type = STACK_MP;
3464         ins->klass = klass;
3465         MONO_ADD_INS (cfg->cbb, ins);
3466
3467         return ins;
3468 }
3469 #endif
3470
3471 static MonoInst*
3472 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
3473 {
3474         int rank;
3475         MonoInst *addr;
3476         MonoMethod *addr_method;
3477         int element_size;
3478
3479         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
3480
3481         if (rank == 1)
3482                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1]);
3483
3484 #ifndef MONO_ARCH_EMULATE_MUL_DIV
3485         /* emit_ldelema_2 depends on OP_LMUL */
3486         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
3487                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
3488         }
3489 #endif
3490
3491         element_size = mono_class_array_element_size (cmethod->klass->element_class);
3492         addr_method = mono_marshal_get_array_address (rank, element_size);
3493         addr = mono_emit_method_call (cfg, addr_method, addr_method->signature, sp, NULL);
3494
3495         return addr;
3496 }
3497
3498 static MonoInst*
3499 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3500 {
3501         MonoInst *ins = NULL;
3502         
3503         static MonoClass *runtime_helpers_class = NULL;
3504         if (! runtime_helpers_class)
3505                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
3506                         "System.Runtime.CompilerServices", "RuntimeHelpers");
3507
3508         if (cmethod->klass == mono_defaults.string_class) {
3509                 if (strcmp (cmethod->name, "get_Chars") == 0) {
3510                         int dreg = alloc_ireg (cfg);
3511                         int index_reg = alloc_preg (cfg);
3512                         int mult_reg = alloc_preg (cfg);
3513                         int add_reg = alloc_preg (cfg);
3514
3515 #if SIZEOF_VOID_P == 8
3516                         /* The array reg is 64 bits but the index reg is only 32 */
3517                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
3518 #else
3519                         index_reg = args [1]->dreg;
3520 #endif  
3521                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
3522
3523 #if defined(__i386__) || defined(__x86_64__)
3524                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
3525                         add_reg = ins->dreg;
3526                         /* Avoid a warning */
3527                         mult_reg = 0;
3528                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
3529                                                                    add_reg, 0);
3530 #else
3531                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
3532                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
3533                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
3534                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
3535 #endif
3536                         type_from_op (ins, NULL, NULL);
3537                         return ins;
3538                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3539                         int dreg = alloc_ireg (cfg);
3540                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
3541                                                                    args [0]->dreg, G_STRUCT_OFFSET (MonoString, length));
3542                         type_from_op (ins, NULL, NULL);
3543
3544                         return ins;
3545                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
3546                         int mult_reg = alloc_preg (cfg);
3547                         int add_reg = alloc_preg (cfg);
3548
3549                         /* The corlib functions check for oob already. */
3550                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
3551                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
3552                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
3553                 } else 
3554                         return NULL;
3555         } else if (cmethod->klass == mono_defaults.object_class) {
3556
3557                 if (strcmp (cmethod->name, "GetType") == 0) {
3558                         int dreg = alloc_preg (cfg);
3559                         int vt_reg = alloc_preg (cfg);
3560                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3561                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
3562                         type_from_op (ins, NULL, NULL);
3563
3564                         return ins;
3565 #if !defined(MONO_ARCH_EMULATE_MUL_DIV) && !defined(HAVE_MOVING_COLLECTOR)
3566                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0) {
3567                         int dreg = alloc_ireg (cfg);
3568                         int t1 = alloc_ireg (cfg);
3569         
3570                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
3571                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
3572                         ins->type = STACK_I4;
3573
3574                         return ins;
3575 #endif
3576                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
3577                         MONO_INST_NEW (cfg, ins, OP_NOP);
3578                         MONO_ADD_INS (cfg->cbb, ins);
3579                         return ins;
3580                 } else
3581                         return NULL;
3582         } else if (cmethod->klass == mono_defaults.array_class) {
3583                 if (cmethod->name [0] != 'g')
3584                         return NULL;
3585
3586                 if (strcmp (cmethod->name, "get_Rank") == 0) {
3587                         int dreg = alloc_ireg (cfg);
3588                         int vtable_reg = alloc_preg (cfg);
3589                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, vtable_reg, 
3590                                                                                    args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3591                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
3592                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3593                         type_from_op (ins, NULL, NULL);
3594
3595                         return ins;
3596                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
3597                         int dreg = alloc_ireg (cfg);
3598
3599                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
3600                                                                    args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
3601                         type_from_op (ins, NULL, NULL);
3602
3603                         return ins;
3604                 } else
3605                         return NULL;
3606         } else if (cmethod->klass == runtime_helpers_class) {
3607
3608                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
3609                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
3610                         return ins;
3611                 } else
3612                         return NULL;
3613         } else if (cmethod->klass == mono_defaults.thread_class) {
3614                 if (strcmp (cmethod->name, "get_CurrentThread") == 0 && (ins = mono_arch_get_thread_intrinsic (cfg))) {
3615                         ins->dreg = alloc_preg (cfg);
3616                         ins->type = STACK_OBJ;
3617                         MONO_ADD_INS (cfg->cbb, ins);
3618                         return ins;
3619                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
3620                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3621                         MONO_ADD_INS (cfg->cbb, ins);
3622                         return ins;
3623                 }
3624         } else if (mini_class_is_system_array (cmethod->klass) &&
3625                         strcmp (cmethod->name, "GetGenericValueImpl") == 0) {
3626                 MonoInst *addr, *store, *load;
3627                 MonoClass *eklass = mono_class_from_mono_type (fsig->params [1]);
3628
3629                 addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1]);
3630                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
3631                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
3632                 return store;
3633         } else if (cmethod->klass->image == mono_defaults.corlib &&
3634                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
3635                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
3636                 ins = NULL;
3637
3638 #if SIZEOF_VOID_P == 8
3639                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
3640                         /* 64 bit reads are already atomic */
3641                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
3642                         ins->dreg = mono_alloc_preg (cfg);
3643                         ins->inst_basereg = args [0]->dreg;
3644                         ins->inst_offset = 0;
3645                         MONO_ADD_INS (cfg->cbb, ins);
3646                 }
3647 #endif
3648
3649 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
3650                 if (strcmp (cmethod->name, "Increment") == 0) {
3651                         MonoInst *ins_iconst;
3652                         guint32 opcode = 0;
3653
3654                         if (fsig->params [0]->type == MONO_TYPE_I4)
3655                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3656 #if SIZEOF_VOID_P == 8
3657                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3658                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3659 #endif
3660                         if (opcode) {
3661                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3662                                 ins_iconst->inst_c0 = 1;
3663                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
3664                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
3665
3666                                 MONO_INST_NEW (cfg, ins, opcode);
3667                                 ins->dreg = mono_alloc_ireg (cfg);
3668                                 ins->inst_basereg = args [0]->dreg;
3669                                 ins->inst_offset = 0;
3670                                 ins->sreg2 = ins_iconst->dreg;
3671                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
3672                                 MONO_ADD_INS (cfg->cbb, ins);
3673                         }
3674                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
3675                         MonoInst *ins_iconst;
3676                         guint32 opcode = 0;
3677
3678                         if (fsig->params [0]->type == MONO_TYPE_I4)
3679                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3680 #if SIZEOF_VOID_P == 8
3681                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3682                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3683 #endif
3684                         if (opcode) {
3685                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
3686                                 ins_iconst->inst_c0 = -1;
3687                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
3688                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
3689
3690                                 MONO_INST_NEW (cfg, ins, opcode);
3691                                 ins->dreg = mono_alloc_ireg (cfg);
3692                                 ins->inst_basereg = args [0]->dreg;
3693                                 ins->inst_offset = 0;
3694                                 ins->sreg2 = ins_iconst->dreg;
3695                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
3696                                 MONO_ADD_INS (cfg->cbb, ins);
3697                         }
3698                 } else if (strcmp (cmethod->name, "Add") == 0) {
3699                         guint32 opcode = 0;
3700
3701                         if (fsig->params [0]->type == MONO_TYPE_I4)
3702                                 opcode = OP_ATOMIC_ADD_NEW_I4;
3703 #if SIZEOF_VOID_P == 8
3704                         else if (fsig->params [0]->type == MONO_TYPE_I8)
3705                                 opcode = OP_ATOMIC_ADD_NEW_I8;
3706 #endif
3707
3708                         if (opcode) {
3709                                 MONO_INST_NEW (cfg, ins, opcode);
3710                                 ins->dreg = mono_alloc_ireg (cfg);
3711                                 ins->inst_basereg = args [0]->dreg;
3712                                 ins->inst_offset = 0;
3713                                 ins->sreg2 = args [1]->dreg;
3714                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
3715                                 MONO_ADD_INS (cfg->cbb, ins);
3716                         }
3717                 }
3718 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
3719
3720 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
3721                 if (strcmp (cmethod->name, "Exchange") == 0) {
3722                         guint32 opcode;
3723
3724                         if (fsig->params [0]->type == MONO_TYPE_I4)
3725                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3726 #if SIZEOF_VOID_P == 8
3727                         else if ((fsig->params [0]->type == MONO_TYPE_I8) ||
3728                                          (fsig->params [0]->type == MONO_TYPE_I) ||
3729                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3730                                 opcode = OP_ATOMIC_EXCHANGE_I8;
3731 #else
3732                         else if ((fsig->params [0]->type == MONO_TYPE_I) ||
3733                                          (fsig->params [0]->type == MONO_TYPE_OBJECT))
3734                                 opcode = OP_ATOMIC_EXCHANGE_I4;
3735 #endif
3736                         else
3737                                 return NULL;
3738
3739                         MONO_INST_NEW (cfg, ins, opcode);
3740                         ins->dreg = mono_alloc_ireg (cfg);
3741                         ins->inst_basereg = args [0]->dreg;
3742                         ins->inst_offset = 0;
3743                         ins->sreg2 = args [1]->dreg;
3744                         MONO_ADD_INS (cfg->cbb, ins);
3745
3746                         switch (fsig->params [0]->type) {
3747                         case MONO_TYPE_I4:
3748                                 ins->type = STACK_I4;
3749                                 break;
3750                         case MONO_TYPE_I8:
3751                         case MONO_TYPE_I:
3752                                 ins->type = STACK_I8;
3753                                 break;
3754                         case MONO_TYPE_OBJECT:
3755                                 ins->type = STACK_OBJ;
3756                                 break;
3757                         default:
3758                                 g_assert_not_reached ();
3759                         }
3760                 }
3761 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
3762  
3763 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS_IMM
3764                 /* 
3765                  * Can't implement CompareExchange methods this way since they have
3766                  * three arguments. We can implement one of the common cases, where the new
3767                  * value is a constant.
3768                  */
3769                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
3770                         if (fsig->params [1]->type == MONO_TYPE_I4 && args [2]->opcode == OP_ICONST) {
3771                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_IMM_I4);
3772                                 ins->dreg = alloc_ireg (cfg);
3773                                 ins->sreg1 = args [0]->dreg;
3774                                 ins->sreg2 = args [1]->dreg;
3775                                 ins->backend.data = GINT_TO_POINTER (args [2]->inst_c0);
3776                                 ins->type = STACK_I4;
3777                                 MONO_ADD_INS (cfg->cbb, ins);
3778                         }
3779                         /* The I8 case is hard to detect, since the arg might be a conv.i8 (iconst) tree */
3780                 }
3781 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS_IMM */
3782
3783                 if (ins)
3784                         return ins;
3785         } else if (cmethod->klass->image == mono_defaults.corlib) {
3786                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
3787                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
3788                         MONO_INST_NEW (cfg, ins, OP_BREAK);
3789                         MONO_ADD_INS (cfg->cbb, ins);
3790                         return ins;
3791                 }
3792                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
3793                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
3794 #ifdef PLATFORM_WIN32
3795                         EMIT_NEW_ICONST (cfg, ins, 1);
3796 #else
3797                         EMIT_NEW_ICONST (cfg, ins, 0);
3798 #endif
3799                         return ins;
3800                 }
3801         } else if (cmethod->klass == mono_defaults.math_class) {
3802                 /* 
3803                  * There is general branches code for Min/Max, but it does not work for 
3804                  * all inputs:
3805                  * http://everything2.com/?node_id=1051618
3806                  */
3807         }
3808
3809         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
3810 }
3811
3812 /*
3813  * This entry point could be used later for arbitrary method
3814  * redirection.
3815  */
3816 inline static MonoInst*
3817 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
3818                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
3819 {
3820         if (method->klass == mono_defaults.string_class) {
3821                 /* managed string allocation support */
3822                 if (strcmp (method->name, "InternalAllocateStr") == 0) {
3823                         MonoInst *iargs [2];
3824                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3825                         MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
3826                         if (!managed_alloc)
3827                                 return NULL;
3828                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3829                         iargs [1] = args [0];
3830                         return mono_emit_method_call (cfg, managed_alloc, mono_method_signature (managed_alloc), iargs, this);
3831                 }
3832         }
3833         return NULL;
3834 }
3835
3836 static void
3837 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp, MonoInst **args)
3838 {
3839         MonoInst *store, *temp;
3840         int i;
3841
3842         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
3843                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
3844
3845                 /*
3846                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
3847                  * would be different than the MonoInst's used to represent arguments, and
3848                  * the ldelema implementation can't deal with that.
3849                  * Solution: When ldelema is used on an inline argument, create a var for 
3850                  * it, emit ldelema on that var, and emit the saving code below in
3851                  * inline_method () if needed.
3852                  */
3853                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
3854                 *args++ = temp;
3855                 EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, *sp);
3856                 store->cil_code = sp [0]->cil_code;
3857                 sp++;
3858         }
3859 }
3860
3861 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
3862 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
3863
3864 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3865 static char*
3866 mono_inline_called_method_name_limit = NULL;
3867 static gboolean check_inline_called_method_name_limit (MonoMethod *called_method) {
3868         char *called_method_name = mono_method_full_name (called_method, TRUE);
3869         int strncmp_result;
3870         
3871         if (mono_inline_called_method_name_limit == NULL) {
3872                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
3873                 if (limit_string != NULL) {
3874                         mono_inline_called_method_name_limit = limit_string;
3875                 } else {
3876                         mono_inline_called_method_name_limit = (char *) "";
3877                 }
3878         }
3879         
3880         strncmp_result = strncmp (called_method_name, mono_inline_called_method_name_limit, strlen (mono_inline_called_method_name_limit));
3881         g_free (called_method_name);
3882         
3883         //return (strncmp_result <= 0);
3884         return (strncmp_result == 0);
3885 }
3886 #endif
3887
3888 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3889 static char*
3890 mono_inline_caller_method_name_limit = NULL;
3891 static gboolean check_inline_caller_method_name_limit (MonoMethod *caller_method) {
3892         char *caller_method_name = mono_method_full_name (caller_method, TRUE);
3893         int strncmp_result;
3894         
3895         if (mono_inline_caller_method_name_limit == NULL) {
3896                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
3897                 if (limit_string != NULL) {
3898                         mono_inline_caller_method_name_limit = limit_string;
3899                 } else {
3900                         mono_inline_caller_method_name_limit = (char *) "";
3901                 }
3902         }
3903         
3904         strncmp_result = strncmp (caller_method_name, mono_inline_caller_method_name_limit, strlen (mono_inline_caller_method_name_limit));
3905         g_free (caller_method_name);
3906         
3907         //return (strncmp_result <= 0);
3908         return (strncmp_result == 0);
3909 }
3910 #endif
3911
3912 static int
3913 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
3914                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_allways)
3915 {
3916         MonoInst *ins, *rvar = NULL;
3917         MonoMethodHeader *cheader;
3918         MonoBasicBlock *ebblock, *sbblock;
3919         int i, costs;
3920         MonoMethod *prev_inlined_method;
3921         MonoInst **prev_locals, **prev_args;
3922         guint prev_real_offset;
3923         GHashTable *prev_cbb_hash;
3924         MonoBasicBlock **prev_cil_offset_to_bb;
3925         MonoBasicBlock *prev_cbb;
3926         unsigned char* prev_cil_start;
3927         guint32 prev_cil_offset_to_bb_len;
3928         MonoMethod *prev_current_method;
3929         MonoGenericContext *prev_generic_context;
3930
3931         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
3932
3933 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
3934         if ((! inline_allways) && ! check_inline_called_method_name_limit (cmethod))
3935                 return 0;
3936 #endif
3937 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
3938         if ((! inline_allways) && ! check_inline_caller_method_name_limit (cfg->method))
3939                 return 0;
3940 #endif
3941
3942         if (cfg->verbose_level > 2)
3943                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
3944
3945         if (!cmethod->inline_info) {
3946                 mono_jit_stats.inlineable_methods++;
3947                 cmethod->inline_info = 1;
3948         }
3949         /* allocate space to store the return value */
3950         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3951                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
3952         }
3953
3954         /* allocate local variables */
3955         cheader = mono_method_get_header (cmethod);
3956         prev_locals = cfg->locals;
3957         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
3958         for (i = 0; i < cheader->num_locals; ++i)
3959                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
3960
3961         prev_args = cfg->args;
3962         
3963         /* allocate start and end blocks */
3964         /* This is needed so if the inline is aborted, we can clean up */
3965         NEW_BBLOCK (cfg, sbblock);
3966         sbblock->real_offset = real_offset;
3967
3968         NEW_BBLOCK (cfg, ebblock);
3969         ebblock->block_num = cfg->num_bblocks++;
3970         ebblock->real_offset = real_offset;
3971
3972         prev_inlined_method = cfg->inlined_method;
3973         cfg->inlined_method = cmethod;
3974         cfg->ret_var_set = FALSE;
3975         prev_real_offset = cfg->real_offset;
3976         prev_cbb_hash = cfg->cbb_hash;
3977         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
3978         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
3979         prev_cil_start = cfg->cil_start;
3980         prev_cbb = cfg->cbb;
3981         prev_current_method = cfg->current_method;
3982         prev_generic_context = cfg->generic_context;
3983
3984         costs = mono_method_to_ir2 (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
3985
3986         cfg->inlined_method = prev_inlined_method;
3987         cfg->real_offset = prev_real_offset;
3988         cfg->cbb_hash = prev_cbb_hash;
3989         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
3990         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
3991         cfg->cil_start = prev_cil_start;
3992         cfg->locals = prev_locals;
3993         cfg->args = prev_args;
3994         cfg->current_method = prev_current_method;
3995         cfg->generic_context = prev_generic_context;
3996
3997         if ((costs >= 0 && costs < 60) || inline_allways) {
3998                 if (cfg->verbose_level > 2)
3999                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4000                 
4001                 mono_jit_stats.inlined_methods++;
4002
4003                 /* always add some code to avoid block split failures */
4004                 MONO_INST_NEW (cfg, ins, OP_NOP);
4005                 MONO_ADD_INS (prev_cbb, ins);
4006
4007                 prev_cbb->next_bb = sbblock;
4008                 link_bblock (cfg, prev_cbb, sbblock);
4009
4010                 /* 
4011                  * Get rid of the begin and end bblocks if possible to aid local
4012                  * optimizations.
4013                  */
4014                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
4015
4016                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
4017                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
4018
4019                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
4020                         MonoBasicBlock *prev = ebblock->in_bb [0];
4021                         mono_merge_basic_blocks (cfg, prev, ebblock);
4022                         cfg->cbb = prev;
4023                 } else {
4024                         cfg->cbb = ebblock;
4025                 }
4026
4027                 if (rvar) {
4028                         /*
4029                          * If the inlined method contains only a throw, then the ret var is not 
4030                          * set, so set it to a dummy value.
4031                          */
4032                         if (!cfg->ret_var_set) {
4033                                 static double r8_0 = 0.0;
4034
4035                                 switch (rvar->type) {
4036                                 case STACK_I4:
4037                                         MONO_EMIT_NEW_ICONST (cfg, rvar->dreg, 0);
4038                                         break;
4039                                 case STACK_I8:
4040                                         MONO_EMIT_NEW_I8CONST (cfg, rvar->dreg, 0);
4041                                         break;
4042                                 case STACK_PTR:
4043                                 case STACK_MP:
4044                                 case STACK_OBJ:
4045                                         MONO_EMIT_NEW_PCONST (cfg, rvar->dreg, 0);
4046                                         break;
4047                                 case STACK_R8:
4048                                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
4049                                         ins->type = STACK_R8;
4050                                         ins->inst_p0 = (void*)&r8_0;
4051                                         ins->dreg = rvar->dreg;
4052                                         MONO_ADD_INS (cfg->cbb, ins);
4053                                         break;
4054                                 case STACK_VTYPE:
4055                                         MONO_EMIT_NEW_VZERO (cfg, rvar->dreg, mono_class_from_mono_type (fsig->ret));
4056                                         break;
4057                                 default:
4058                                         g_assert_not_reached ();
4059                                 }
4060                         }
4061
4062                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4063                         *sp++ = ins;
4064                 }
4065                 return costs + 1;
4066         } else {
4067                 if (cfg->verbose_level > 2)
4068                         printf ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4069                 cfg->exception_type = MONO_EXCEPTION_NONE;
4070                 mono_loader_clear_error ();
4071
4072                 /* This gets rid of the newly added bblocks */
4073                 cfg->cbb = prev_cbb;
4074         }
4075         return 0;
4076 }
4077
4078 /*
4079  * Some of these comments may well be out-of-date.
4080  * Design decisions: we do a single pass over the IL code (and we do bblock 
4081  * splitting/merging in the few cases when it's required: a back jump to an IL
4082  * address that was not already seen as bblock starting point).
4083  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4084  * Complex operations are decomposed in simpler ones right away. We need to let the 
4085  * arch-specific code peek and poke inside this process somehow (except when the 
4086  * optimizations can take advantage of the full semantic info of coarse opcodes).
4087  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4088  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4089  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4090  * opcode with value bigger than OP_LAST.
4091  * At this point the IR can be handed over to an interpreter, a dumb code generator
4092  * or to the optimizing code generator that will translate it to SSA form.
4093  *
4094  * Profiling directed optimizations.
4095  * We may compile by default with few or no optimizations and instrument the code
4096  * or the user may indicate what methods to optimize the most either in a config file
4097  * or through repeated runs where the compiler applies offline the optimizations to 
4098  * each method and then decides if it was worth it.
4099  */
4100
4101 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
4102 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
4103 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
4104 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
4105 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
4106 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
4107 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
4108 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; goto load_error;}
4109
4110 /* offset from br.s -> br like opcodes */
4111 #define BIG_BRANCH_OFFSET 13
4112
4113 static gboolean
4114 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
4115 {
4116         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
4117
4118         return b == NULL || b == bb;
4119 }
4120
4121 static int
4122 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
4123 {
4124         unsigned char *ip = start;
4125         unsigned char *target;
4126         int i;
4127         guint cli_addr;
4128         MonoBasicBlock *bblock;
4129         const MonoOpcode *opcode;
4130
4131         while (ip < end) {
4132                 cli_addr = ip - start;
4133                 i = mono_opcode_value ((const guint8 **)&ip, end);
4134                 if (i < 0)
4135                         UNVERIFIED;
4136                 opcode = &mono_opcodes [i];
4137                 switch (opcode->argument) {
4138                 case MonoInlineNone:
4139                         ip++; 
4140                         break;
4141                 case MonoInlineString:
4142                 case MonoInlineType:
4143                 case MonoInlineField:
4144                 case MonoInlineMethod:
4145                 case MonoInlineTok:
4146                 case MonoInlineSig:
4147                 case MonoShortInlineR:
4148                 case MonoInlineI:
4149                         ip += 5;
4150                         break;
4151                 case MonoInlineVar:
4152                         ip += 3;
4153                         break;
4154                 case MonoShortInlineVar:
4155                 case MonoShortInlineI:
4156                         ip += 2;
4157                         break;
4158                 case MonoShortInlineBrTarget:
4159                         target = start + cli_addr + 2 + (signed char)ip [1];
4160                         GET_BBLOCK (cfg, bblock, target);
4161                         ip += 2;
4162                         if (ip < end)
4163                                 GET_BBLOCK (cfg, bblock, ip);
4164                         break;
4165                 case MonoInlineBrTarget:
4166                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
4167                         GET_BBLOCK (cfg, bblock, target);
4168                         ip += 5;
4169                         if (ip < end)
4170                                 GET_BBLOCK (cfg, bblock, ip);
4171                         break;
4172                 case MonoInlineSwitch: {
4173                         guint32 n = read32 (ip + 1);
4174                         guint32 j;
4175                         ip += 5;
4176                         cli_addr += 5 + 4 * n;
4177                         target = start + cli_addr;
4178                         GET_BBLOCK (cfg, bblock, target);
4179                         
4180                         for (j = 0; j < n; ++j) {
4181                                 target = start + cli_addr + (gint32)read32 (ip);
4182                                 GET_BBLOCK (cfg, bblock, target);
4183                                 ip += 4;
4184                         }
4185                         break;
4186                 }
4187                 case MonoInlineR:
4188                 case MonoInlineI8:
4189                         ip += 9;
4190                         break;
4191                 default:
4192                         g_assert_not_reached ();
4193                 }
4194
4195                 if (i == CEE_THROW) {
4196                         unsigned char *bb_start = ip - 1;
4197                         
4198                         /* Find the start of the bblock containing the throw */
4199                         bblock = NULL;
4200                         while ((bb_start >= start) && !bblock) {
4201                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
4202                                 bb_start --;
4203                         }
4204                         if (bblock)
4205                                 bblock->out_of_line = 1;
4206                 }
4207         }
4208         return 0;
4209 unverified:
4210         *pos = ip;
4211         return 1;
4212 }
4213
4214 static inline MonoMethod *
4215 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4216 {
4217         MonoMethod *method;
4218
4219         if (m->wrapper_type != MONO_WRAPPER_NONE)
4220                 return mono_method_get_wrapper_data (m, token);
4221
4222         method = mono_get_method_full (m->klass->image, token, klass, context);
4223
4224         return method;
4225 }
4226
4227 static inline MonoMethod *
4228 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
4229 {
4230         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
4231
4232         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
4233                 return NULL;
4234
4235         return method;
4236 }
4237
4238 static inline MonoClass*
4239 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
4240 {
4241         MonoClass *klass;
4242
4243         if (method->wrapper_type != MONO_WRAPPER_NONE)
4244                 klass = mono_method_get_wrapper_data (method, token);
4245         else
4246                 klass = mono_class_get_full (method->klass->image, token, context);
4247         if (klass)
4248                 mono_class_init (klass);
4249         return klass;
4250 }
4251
4252 /*
4253  * Returns TRUE if the JIT should abort inlining because "callee"
4254  * is influenced by security attributes.
4255  */
4256 static
4257 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
4258 {
4259         guint32 result;
4260         
4261         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
4262                 return TRUE;
4263         }
4264         
4265         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
4266         if (result == MONO_JIT_SECURITY_OK)
4267                 return FALSE;
4268
4269         if (result == MONO_JIT_LINKDEMAND_ECMA) {
4270                 /* Generate code to throw a SecurityException before the actual call/link */
4271                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4272                 MonoInst *args [2];
4273
4274                 NEW_ICONST (cfg, args [0], 4);
4275                 NEW_METHODCONST (cfg, args [1], caller);
4276                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, mono_method_signature (secman->linkdemandsecurityexception), args, NULL);
4277         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
4278                  /* don't hide previous results */
4279                 cfg->exception_type = MONO_EXCEPTION_SECURITY_LINKDEMAND;
4280                 cfg->exception_data = result;
4281                 return TRUE;
4282         }
4283         
4284         return FALSE;
4285 }
4286
4287 static MonoMethod*
4288 method_access_exception (void)
4289 {
4290         static MonoMethod *method = NULL;
4291
4292         if (!method) {
4293                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4294                 method = mono_class_get_method_from_name (secman->securitymanager,
4295                                                           "MethodAccessException", 2);
4296         }
4297         g_assert (method);
4298         return method;
4299 }
4300
4301 static void
4302 emit_throw_method_access_exception (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4303                                     MonoBasicBlock *bblock, unsigned char *ip)
4304 {
4305         MonoMethod *thrower = method_access_exception ();
4306         MonoInst *args [2];
4307
4308         EMIT_NEW_METHODCONST (cfg, args [0], caller);
4309         EMIT_NEW_METHODCONST (cfg, args [1], callee);
4310         mono_emit_method_call (cfg, thrower, mono_method_signature (thrower), args, NULL);
4311 }
4312
4313 static MonoMethod*
4314 verification_exception (void)
4315 {
4316         static MonoMethod *method = NULL;
4317
4318         if (!method) {
4319                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
4320                 method = mono_class_get_method_from_name (secman->securitymanager,
4321                                                           "VerificationException", 0);
4322         }
4323         g_assert (method);
4324         return method;
4325 }
4326
4327 static void
4328 emit_throw_verification_exception (MonoCompile *cfg, MonoBasicBlock *bblock, unsigned char *ip)
4329 {
4330         MonoMethod *thrower = verification_exception ();
4331
4332         mono_emit_method_call (cfg, thrower, mono_method_signature (thrower), NULL, NULL);
4333 }
4334
4335 static void
4336 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
4337                                          MonoBasicBlock *bblock, unsigned char *ip)
4338 {
4339         MonoSecurityCoreCLRLevel caller_level = mono_security_core_clr_method_level (caller, TRUE);
4340         MonoSecurityCoreCLRLevel callee_level = mono_security_core_clr_method_level (callee, TRUE);
4341         gboolean is_safe = TRUE;
4342
4343         if (!(caller_level >= callee_level ||
4344                         caller_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL ||
4345                         callee_level == MONO_SECURITY_CORE_CLR_SAFE_CRITICAL)) {
4346                 is_safe = FALSE;
4347         }
4348
4349         if (!is_safe)
4350                 emit_throw_method_access_exception (cfg, caller, callee, bblock, ip);
4351 }
4352
4353 static gboolean
4354 method_is_safe (MonoMethod *method)
4355 {
4356         /*
4357         if (strcmp (method->name, "unsafeMethod") == 0)
4358                 return FALSE;
4359         */
4360         return TRUE;
4361 }
4362
4363 /*
4364  * Check that the IL instructions at ip are the array initialization
4365  * sequence and return the pointer to the data and the size.
4366  */
4367 static const char*
4368 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size)
4369 {
4370         /*
4371          * newarr[System.Int32]
4372          * dup
4373          * ldtoken field valuetype ...
4374          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
4375          */
4376         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
4377                 guint32 token = read32 (ip + 7);
4378                 guint32 field_token = read32 (ip + 2);
4379                 guint32 field_index = field_token & 0xffffff;
4380                 guint32 rva;
4381                 const char *data_ptr;
4382                 int size = 0;
4383                 MonoMethod *cmethod;
4384                 MonoClass *dummy_class;
4385                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
4386                 int dummy_align;
4387
4388                 if (!field)
4389                         return NULL;
4390
4391                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
4392                 if (!cmethod)
4393                         return NULL;
4394                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
4395                         return NULL;
4396                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
4397                 case MONO_TYPE_BOOLEAN:
4398                 case MONO_TYPE_I1:
4399                 case MONO_TYPE_U1:
4400                         size = 1; break;
4401                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
4402 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
4403                 case MONO_TYPE_CHAR:
4404                 case MONO_TYPE_I2:
4405                 case MONO_TYPE_U2:
4406                         size = 2; break;
4407                 case MONO_TYPE_I4:
4408                 case MONO_TYPE_U4:
4409                 case MONO_TYPE_R4:
4410                         size = 4; break;
4411                 case MONO_TYPE_R8:
4412 #ifdef ARM_FPU_FPA
4413                         return NULL; /* stupid ARM FP swapped format */
4414 #endif
4415                 case MONO_TYPE_I8:
4416                 case MONO_TYPE_U8:
4417                         size = 8; break;
4418 #endif
4419                 default:
4420                         return NULL;
4421                 }
4422                 size *= len;
4423                 if (size > mono_type_size (field->type, &dummy_align))
4424                     return NULL;
4425                 *out_size = size;
4426                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
4427                 field_index = read32 (ip + 2) & 0xffffff;
4428                 mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
4429                 data_ptr = mono_image_rva_map (method->klass->image, rva);
4430                 /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
4431                 /* for aot code we do the lookup on load */
4432                 if (aot && data_ptr)
4433                         return GUINT_TO_POINTER (rva);
4434                 return data_ptr;
4435         }
4436         return NULL;
4437 }
4438
4439 static void
4440 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
4441 {
4442         char *method_fname = mono_method_full_name (method, TRUE);
4443         char *method_code;
4444
4445         if (mono_method_get_header (method)->code_size == 0)
4446                 method_code = g_strdup ("method body is empty.");
4447         else
4448                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
4449         cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
4450         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
4451         g_free (method_fname);
4452         g_free (method_code);
4453 }
4454
4455 static void
4456 set_exception_object (MonoCompile *cfg, MonoException *exception)
4457 {
4458         cfg->exception_type = MONO_EXCEPTION_OBJECT_SUPPLIED;
4459         MONO_GC_REGISTER_ROOT (cfg->exception_ptr);
4460         cfg->exception_ptr = exception;
4461 }
4462
4463 static gboolean
4464 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4465 {
4466         MonoType *type;
4467
4468         if (cfg->generic_sharing_context)
4469                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
4470         else
4471                 type = &klass->byval_arg;
4472         return MONO_TYPE_IS_REFERENCE (type);
4473 }
4474
4475 /**
4476  * mono_decompose_array_access_opts:
4477  *
4478  *  Decompose array access opcodes.
4479  */
4480 void
4481 mono_decompose_array_access_opts (MonoCompile *cfg)
4482 {
4483         MonoBasicBlock *bb, *first_bb;
4484
4485         /*
4486          * Unlike decompose_long_opts, this pass does not alter the CFG of the method so it 
4487          * can be executed anytime. It should be run before decompose_long
4488          */
4489
4490         /**
4491          * Create a dummy bblock and emit code into it so we can use the normal 
4492          * code generation macros.
4493          */
4494         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
4495         first_bb = cfg->cbb;
4496
4497         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4498                 MonoInst *ins;
4499                 MonoInst *prev = NULL;
4500                 MonoInst *dest;
4501                 MonoInst *iargs [3];
4502                 gboolean restart;
4503
4504                 if (!bb->has_array_access)
4505                         continue;
4506
4507                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE DECOMPOSE-ARRAY-ACCESS-OPTS ");
4508
4509                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
4510                 restart = TRUE;
4511
4512                 while (restart) {
4513                         restart = FALSE;
4514
4515                         for (ins = bb->code; ins; ins = ins->next) {
4516                                 switch (ins->opcode) {
4517                                 case OP_LDLEN:
4518                                         NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg, ins->sreg1,
4519                                                                           G_STRUCT_OFFSET (MonoArray, max_length));
4520                                         MONO_ADD_INS (cfg->cbb, dest);
4521                                         break;
4522                                 case OP_BOUNDS_CHECK:
4523                                         MONO_ARCH_EMIT_BOUNDS_CHECK (cfg, ins->sreg1, ins->inst_imm, ins->sreg2);
4524                                         break;
4525                                 case OP_NEWARR:
4526                                         if (cfg->opt & MONO_OPT_SHARED) {
4527                                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4528                                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], ins->inst_newa_class);
4529                                                 MONO_INST_NEW (cfg, iargs [2], OP_MOVE);
4530                                                 iargs [2]->dreg = ins->sreg1;
4531
4532                                                 dest = mono_emit_jit_icall (cfg, mono_array_new, iargs);
4533                                                 dest->dreg = ins->dreg;
4534                                         } else {
4535                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, mono_array_class_get (ins->inst_newa_class, 1));
4536
4537                                                 g_assert (vtable);
4538                                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
4539                                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
4540                                                 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
4541                                                 iargs [1]->dreg = ins->sreg1;
4542
4543                                                 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
4544                                                 dest->dreg = ins->dreg;
4545                                         }
4546                                         break;
4547                                 default:
4548                                         break;
4549                                 }
4550
4551                                 g_assert (cfg->cbb == first_bb);
4552
4553                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
4554                                         /* Replace the original instruction with the new code sequence */
4555
4556                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
4557                                         first_bb->code = first_bb->last_ins = NULL;
4558                                         first_bb->in_count = first_bb->out_count = 0;
4559                                         cfg->cbb = first_bb;
4560                                 }
4561                                 else
4562                                         prev = ins;
4563                         }
4564                 }
4565
4566                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
4567         }
4568 }
4569
4570 typedef union {
4571         guint32 vali [2];
4572         gint64 vall;
4573         double vald;
4574 } DVal;
4575
4576 #ifdef MONO_ARCH_SOFT_FLOAT
4577
4578 /**
4579  * mono_handle_soft_float:
4580  *
4581  *  Soft float support on ARM. We store each double value in a pair of integer vregs,
4582  * similar to long support on 32 bit platforms. 32 bit float values require special
4583  * handling when used as locals, arguments, and in calls.
4584  * One big problem with soft-float is that there are few r4 test cases in our test suite.
4585  */
4586 void
4587 mono_handle_soft_float (MonoCompile *cfg)
4588 {
4589         MonoBasicBlock *bb, *first_bb;
4590
4591         /*
4592          * This pass creates long opcodes, so it should be run before decompose_long_opts ().
4593          */
4594
4595         /**
4596          * Create a dummy bblock and emit code into it so we can use the normal 
4597          * code generation macros.
4598          */
4599         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
4600         first_bb = cfg->cbb;
4601
4602         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4603                 MonoInst *ins;
4604                 MonoInst *prev = NULL;
4605                 gboolean restart;
4606
4607                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
4608
4609                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
4610                 restart = TRUE;
4611
4612                 while (restart) {
4613                         restart = FALSE;
4614
4615                         for (ins = bb->code; ins; ins = ins->next) {
4616                                 const char *spec = INS_INFO (ins->opcode);
4617
4618                                 /* Most fp operations are handled automatically by opcode emulation */
4619
4620                                 switch (ins->opcode) {
4621                                 case OP_R8CONST: {
4622                                         DVal d;
4623                                         d.vald = *(double*)ins->inst_p0;
4624                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
4625                                         break;
4626                                 }
4627                                 case OP_R4CONST: {
4628                                         DVal d;
4629                                         /* We load the r8 value */
4630                                         d.vald = *(float*)ins->inst_p0;
4631                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
4632                                         break;
4633                                 }
4634                                 case OP_FMOVE:
4635                                         ins->opcode = OP_LMOVE;
4636                                         break;
4637                                 case OP_FGETLOW32:
4638                                         ins->opcode = OP_MOVE;
4639                                         ins->sreg1 = ins->sreg1 + 1;
4640                                         break;
4641                                 case OP_FGETHIGH32:
4642                                         ins->opcode = OP_MOVE;
4643                                         ins->sreg1 = ins->sreg1 + 2;
4644                                         break;
4645                                 case OP_SETFRET: {
4646                                         int reg = ins->sreg1;
4647
4648                                         ins->opcode = OP_SETLRET;
4649                                         ins->dreg = -1;
4650                                         ins->sreg1 = reg + 1;
4651                                         ins->sreg2 = reg + 2;
4652                                         break;
4653                                 }
4654                                 case OP_LOADR8_MEMBASE:
4655                                         ins->opcode = OP_LOADI8_MEMBASE;
4656                                         break;
4657                                 case OP_STORER8_MEMBASE_REG:
4658                                         ins->opcode = OP_STOREI8_MEMBASE_REG;
4659                                         break;
4660                                 case OP_STORER4_MEMBASE_REG: {
4661                                         MonoInst *iargs [2];
4662                                         int addr_reg;
4663
4664                                         /* Arg 1 is the double value */
4665                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
4666                                         iargs [0]->dreg = ins->sreg1;
4667
4668                                         /* Arg 2 is the address to store to */
4669                                         addr_reg = mono_alloc_preg (cfg);
4670                                         EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
4671                                         mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
4672                                         restart = TRUE;
4673                                         break;
4674                                 }
4675                                 case OP_LOADR4_MEMBASE: {
4676                                         MonoInst *iargs [1];
4677                                         MonoInst *conv;
4678                                         int addr_reg;
4679
4680                                         addr_reg = mono_alloc_preg (cfg);
4681                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
4682                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
4683                                         conv->dreg = ins->dreg;
4684                                         break;
4685                                 }                                       
4686                                 case OP_FCALL:
4687                                 case OP_FCALL_REG:
4688                                 case OP_FCALL_MEMBASE: {
4689                                         MonoCallInst *call = (MonoCallInst*)ins;
4690                                         if (call->signature->ret->type == MONO_TYPE_R4) {
4691                                                 MonoCallInst *call2;
4692                                                 MonoInst *iargs [1];
4693                                                 MonoInst *conv;
4694
4695                                                 /* Convert the call into a call returning an int */
4696                                                 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
4697                                                 memcpy (call2, call, sizeof (MonoCallInst));
4698                                                 switch (ins->opcode) {
4699                                                 case OP_FCALL:
4700                                                         call2->inst.opcode = OP_CALL;
4701                                                         break;
4702                                                 case OP_FCALL_REG:
4703                                                         call2->inst.opcode = OP_CALL_REG;
4704                                                         break;
4705                                                 case OP_FCALL_MEMBASE:
4706                                                         call2->inst.opcode = OP_CALL_MEMBASE;
4707                                                         break;
4708                                                 default:
4709                                                         g_assert_not_reached ();
4710                                                 }
4711                                                 call2->inst.dreg = mono_alloc_ireg (cfg);
4712                                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
4713
4714                                                 /* FIXME: Optimize this */
4715
4716                                                 /* Emit an r4->r8 conversion */
4717                                                 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
4718                                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
4719                                                 conv->dreg = ins->dreg;
4720                                         } else {
4721                                                 switch (ins->opcode) {
4722                                                 case OP_FCALL:
4723                                                         ins->opcode = OP_LCALL;
4724                                                         break;
4725                                                 case OP_FCALL_REG:
4726                                                         ins->opcode = OP_LCALL_REG;
4727                                                         break;
4728                                                 case OP_FCALL_MEMBASE:
4729                                                         ins->opcode = OP_LCALL_MEMBASE;
4730                                                         break;
4731                                                 default:
4732                                                         g_assert_not_reached ();
4733                                                 }
4734                                         }
4735                                         break;
4736                                 }
4737                                 case OP_FCOMPARE: {
4738                                         MonoJitICallInfo *info;
4739                                         MonoInst *iargs [2];
4740                                         MonoInst *call, *cmp, *br;
4741
4742                                         /* Convert fcompare+fbcc to icall+icompare+beq */
4743
4744                                         info = mono_find_jit_opcode_emulation (ins->next->opcode);
4745                                         g_assert (info);
4746
4747                                         /* Create dummy MonoInst's for the arguments */
4748                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
4749                                         iargs [0]->dreg = ins->sreg1;
4750                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
4751                                         iargs [1]->dreg = ins->sreg2;
4752
4753                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
4754
4755                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
4756                                         cmp->sreg1 = call->dreg;
4757                                         cmp->inst_imm = 0;
4758                                         MONO_ADD_INS (cfg->cbb, cmp);
4759                                         
4760                                         MONO_INST_NEW (cfg, br, OP_IBNE_UN);
4761                                         br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
4762                                         br->inst_true_bb = ins->next->inst_true_bb;
4763                                         br->inst_false_bb = ins->next->inst_false_bb;
4764                                         MONO_ADD_INS (cfg->cbb, br);
4765
4766                                         /* The call sequence might include fp ins */
4767                                         restart = TRUE;
4768
4769                                         /* Skip fbcc or fccc */
4770                                         NULLIFY_INS (ins->next);
4771                                         break;
4772                                 }
4773                                 case OP_FCEQ:
4774                                 case OP_FCGT:
4775                                 case OP_FCGT_UN:
4776                                 case OP_FCLT:
4777                                 case OP_FCLT_UN: {
4778                                         MonoJitICallInfo *info;
4779                                         MonoInst *iargs [2];
4780                                         MonoInst *call;
4781
4782                                         /* Convert fccc to icall+icompare+iceq */
4783
4784                                         info = mono_find_jit_opcode_emulation (ins->opcode);
4785                                         g_assert (info);
4786
4787                                         /* Create dummy MonoInst's for the arguments */
4788                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
4789                                         iargs [0]->dreg = ins->sreg1;
4790                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
4791                                         iargs [1]->dreg = ins->sreg2;
4792
4793                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
4794
4795                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
4796                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
4797
4798                                         /* The call sequence might include fp ins */
4799                                         restart = TRUE;
4800                                         break;
4801                                 }
4802                                 default:
4803                                         if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
4804                                                 mono_print_ins (ins);
4805                                                 g_assert_not_reached ();
4806                                         }
4807                                         break;
4808                                 }
4809
4810                                 g_assert (cfg->cbb == first_bb);
4811
4812                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
4813                                         /* Replace the original instruction with the new code sequence */
4814
4815                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
4816                                         first_bb->code = first_bb->last_ins = NULL;
4817                                         first_bb->in_count = first_bb->out_count = 0;
4818                                         cfg->cbb = first_bb;
4819                                 }
4820                                 else
4821                                         prev = ins;
4822                         }
4823                 }
4824
4825                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
4826         }
4827
4828         mono_decompose_long_opts (cfg);
4829 }
4830
4831 #endif
4832
4833 /*
4834  * mono_method_to_ir: translates IL into basic blocks containing trees
4835  */
4836 int
4837 mono_method_to_ir2 (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
4838                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
4839                    guint inline_offset, gboolean is_virtual_call)
4840 {
4841         MonoInst *ins, **sp, **stack_start;
4842         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
4843         MonoMethod *cmethod, *method_definition;
4844         MonoInst **arg_array;
4845         MonoMethodHeader *header;
4846         MonoImage *image;
4847         guint32 token, ins_flag;
4848         MonoClass *klass;
4849         MonoClass *constrained_call = NULL;
4850         unsigned char *ip, *end, *target, *err_pos;
4851         static double r8_0 = 0.0;
4852         MonoMethodSignature *sig;
4853         MonoGenericContext *generic_context = NULL;
4854         MonoGenericContainer *generic_container = NULL;
4855         MonoType **param_types;
4856         GList *bb_recheck = NULL, *tmp;
4857         int i, n, start_new_bblock, dreg;
4858         int num_calls = 0, inline_costs = 0;
4859         int breakpoint_id = 0;
4860         guint num_args;
4861         MonoBoolean security, pinvoke;
4862         MonoSecurityManager* secman = NULL;
4863         MonoDeclSecurityActions actions;
4864         GSList *class_inits = NULL;
4865         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
4866         int context_used;
4867
4868         /* serialization and xdomain stuff may need access to private fields and methods */
4869         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
4870         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
4871         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
4872         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
4873         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
4874         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
4875
4876         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
4877
4878         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
4879         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
4880         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
4881         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
4882
4883         image = method->klass->image;
4884         header = mono_method_get_header (method);
4885         generic_container = mono_method_get_generic_container (method);
4886         sig = mono_method_signature (method);
4887         num_args = sig->hasthis + sig->param_count;
4888         ip = (unsigned char*)header->code;
4889         cfg->cil_start = ip;
4890         end = ip + header->code_size;
4891         mono_jit_stats.cil_code_size += header->code_size;
4892
4893         method_definition = method;
4894         while (method_definition->is_inflated) {
4895                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
4896                 method_definition = imethod->declaring;
4897         }
4898
4899         /* SkipVerification is not allowed if core-clr is enabled */
4900         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
4901                 dont_verify = TRUE;
4902                 dont_verify_stloc = TRUE;
4903         }
4904
4905         if (!dont_verify && mini_method_verify (cfg, method_definition))
4906                 goto exception_exit;
4907
4908         if (sig->is_inflated)
4909                 generic_context = mono_method_get_context (method);
4910         else if (generic_container)
4911                 generic_context = &generic_container->context;
4912         cfg->generic_context = generic_context;
4913
4914         if (!cfg->generic_sharing_context)
4915                 g_assert (!sig->has_type_parameters);
4916
4917         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
4918                 g_assert (method->is_inflated);
4919                 g_assert (mono_method_get_context (method)->method_inst);
4920         }
4921         if (method->is_inflated && mono_method_get_context (method)->method_inst)
4922                 g_assert (sig->generic_param_count);
4923
4924         if (cfg->method == method) {
4925                 cfg->real_offset = 0;
4926         } else {
4927                 cfg->real_offset = inline_offset;
4928         }
4929
4930         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
4931         cfg->cil_offset_to_bb_len = header->code_size;
4932
4933         cfg->current_method = method;
4934
4935         if (cfg->verbose_level > 2)
4936                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
4937
4938         dont_inline = g_list_prepend (dont_inline, method);
4939         if (cfg->method == method) {
4940
4941                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
4942                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
4943
4944                 /* ENTRY BLOCK */
4945                 NEW_BBLOCK (cfg, start_bblock);
4946                 cfg->bb_entry = start_bblock;
4947                 start_bblock->cil_code = NULL;
4948                 start_bblock->cil_length = 0;
4949
4950                 /* EXIT BLOCK */
4951                 NEW_BBLOCK (cfg, end_bblock);
4952                 cfg->bb_exit = end_bblock;
4953                 end_bblock->cil_code = NULL;
4954                 end_bblock->cil_length = 0;
4955                 g_assert (cfg->num_bblocks == 2);
4956
4957                 arg_array = alloca (sizeof (MonoInst *) * num_args);
4958                 for (i = num_args - 1; i >= 0; i--)
4959                         arg_array [i] = cfg->args [i];
4960
4961                 if (header->num_clauses) {
4962                         cfg->spvars = g_hash_table_new (NULL, NULL);
4963                         cfg->exvars = g_hash_table_new (NULL, NULL);
4964                 }
4965                 /* handle exception clauses */
4966                 for (i = 0; i < header->num_clauses; ++i) {
4967                         MonoBasicBlock *try_bb;
4968                         MonoExceptionClause *clause = &header->clauses [i];
4969                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
4970                         try_bb->real_offset = clause->try_offset;
4971                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
4972                         tblock->real_offset = clause->handler_offset;
4973                         tblock->flags |= BB_EXCEPTION_HANDLER;
4974
4975                         link_bblock (cfg, try_bb, tblock);
4976
4977                         if (*(ip + clause->handler_offset) == CEE_POP)
4978                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
4979
4980                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
4981                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
4982                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
4983                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
4984                                 MONO_ADD_INS (tblock, ins);
4985
4986                                 /* todo: is a fault block unsafe to optimize? */
4987                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
4988                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
4989                         }
4990
4991
4992                         /*printf ("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);
4993                           while (p < end) {
4994                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
4995                           }*/
4996                         /* catch and filter blocks get the exception object on the stack */
4997                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
4998                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
4999                                 MonoInst *dummy_use;
5000
5001                                 /* mostly like handle_stack_args (), but just sets the input args */
5002                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
5003                                 tblock->in_scount = 1;
5004                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5005                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5006
5007                                 /* 
5008                                  * Add a dummy use for the exvar so its liveness info will be
5009                                  * correct.
5010                                  */
5011                                 cfg->cbb = tblock;
5012                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
5013                                 
5014                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5015                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5016                                         tblock->real_offset = clause->data.filter_offset;
5017                                         tblock->in_scount = 1;
5018                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5019                                         /* The filter block shares the exvar with the handler block */
5020                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5021                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5022                                         MONO_ADD_INS (tblock, ins);
5023                                 }
5024                         }
5025
5026                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5027                                         clause->data.catch_class &&
5028                                         cfg->generic_sharing_context &&
5029                                         mono_class_check_context_used (clause->data.catch_class)) {
5030                                 if (mono_method_get_context (method)->method_inst)
5031                                         GENERIC_SHARING_FAILURE (CEE_NOP);
5032
5033                                 /*
5034                                  * In shared generic code with catch
5035                                  * clauses containing type variables
5036                                  * the exception handling code has to
5037                                  * be able to get to the rgctx.
5038                                  * Therefore we have to make sure that
5039                                  * the vtable/mrgctx argument (for
5040                                  * static or generic methods) or the
5041                                  * "this" argument (for non-static
5042                                  * methods) are live.
5043                                  */
5044                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5045                                                 mini_method_get_context (method)->method_inst) {
5046                                         mono_get_vtable_var (cfg);
5047                                 } else {
5048                                         MonoInst *dummy_use;
5049
5050                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
5051                                 }
5052                         }
5053                 }
5054         } else {
5055                 arg_array = alloca (sizeof (MonoInst *) * num_args);
5056                 cfg->cbb = start_bblock;
5057                 mono_save_args (cfg, sig, inline_args, arg_array);
5058         }
5059
5060         /* FIRST CODE BLOCK */
5061         NEW_BBLOCK (cfg, bblock);
5062         bblock->cil_code = ip;
5063         cfg->cbb = bblock;
5064         cfg->ip = ip;
5065
5066         ADD_BBLOCK (cfg, bblock);
5067
5068         if (cfg->method == method) {
5069                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5070                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5071                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5072                         MONO_ADD_INS (bblock, ins);
5073                 }
5074         }
5075
5076         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5077                 secman = mono_security_manager_get_methods ();
5078
5079         security = (secman && mono_method_has_declsec (method));
5080         /* at this point having security doesn't mean we have any code to generate */
5081         if (security && (cfg->method == method)) {
5082                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5083                  * And we do not want to enter the next section (with allocation) if we
5084                  * have nothing to generate */
5085                 security = mono_declsec_get_demands (method, &actions);
5086         }
5087
5088         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5089         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5090         if (pinvoke) {
5091                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5092                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5093                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5094
5095                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5096                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5097                                 pinvoke = FALSE;
5098                         }
5099                         if (custom)
5100                                 mono_custom_attrs_free (custom);
5101
5102                         if (pinvoke) {
5103                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5104                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5105                                         pinvoke = FALSE;
5106                                 }
5107                                 if (custom)
5108                                         mono_custom_attrs_free (custom);
5109                         }
5110                 } else {
5111                         /* not a P/Invoke after all */
5112                         pinvoke = FALSE;
5113                 }
5114         }
5115         
5116         if ((header->init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5117                 /* we use a separate basic block for the initialization code */
5118                 NEW_BBLOCK (cfg, init_localsbb);
5119                 cfg->bb_init = init_localsbb;
5120                 init_localsbb->real_offset = cfg->real_offset;
5121                 start_bblock->next_bb = init_localsbb;
5122                 init_localsbb->next_bb = bblock;
5123                 link_bblock (cfg, start_bblock, init_localsbb);
5124                 link_bblock (cfg, init_localsbb, bblock);
5125                 
5126                 cfg->cbb = init_localsbb;
5127         } else {
5128                 start_bblock->next_bb = bblock;
5129                 link_bblock (cfg, start_bblock, bblock);
5130         }
5131
5132         /* at this point we know, if security is TRUE, that some code needs to be generated */
5133         if (security && (cfg->method == method)) {
5134                 MonoInst *args [2];
5135
5136                 mono_jit_stats.cas_demand_generation++;
5137
5138                 if (actions.demand.blob) {
5139                         /* Add code for SecurityAction.Demand */
5140                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5141                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
5142                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5143                         mono_emit_method_call (cfg, secman->demand, mono_method_signature (secman->demand), args, NULL);
5144                 }
5145                 if (actions.noncasdemand.blob) {
5146                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5147                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5148                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5149                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5150                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5151                         mono_emit_method_call (cfg, secman->demand, mono_method_signature (secman->demand), args, NULL);
5152                 }
5153                 if (actions.demandchoice.blob) {
5154                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5155                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5156                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5157                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5158                         mono_emit_method_call (cfg, secman->demandchoice, mono_method_signature (secman->demandchoice), args, NULL);
5159                 }
5160         }
5161
5162         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5163         if (pinvoke) {
5164                 mono_emit_method_call (cfg, secman->demandunmanaged, mono_method_signature (secman->demandunmanaged), NULL, NULL);
5165         }
5166
5167         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5168                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5169                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5170                         if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5171                                 if (!(method->klass && method->klass->image &&
5172                                                 mono_security_core_clr_is_platform_image (method->klass->image))) {
5173                                         emit_throw_method_access_exception (cfg, method, wrapped, bblock, ip);
5174                                 }
5175                         }
5176                 }
5177                 if (!method_is_safe (method))
5178                         emit_throw_verification_exception (cfg, bblock, ip);
5179         }
5180
5181         if (header->code_size == 0)
5182                 UNVERIFIED;
5183
5184         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
5185                 ip = err_pos;
5186                 UNVERIFIED;
5187         }
5188
5189         if (cfg->method == method)
5190                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5191
5192         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5193         if (sig->hasthis)
5194                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5195         for (n = 0; n < sig->param_count; ++n)
5196                 param_types [n + sig->hasthis] = sig->params [n];
5197         for (n = 0; n < header->num_locals; ++n) {
5198                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5199                         UNVERIFIED;
5200         }
5201         class_inits = NULL;
5202
5203         /* add a check for this != NULL to inlined methods */
5204         if (is_virtual_call) {
5205                 MonoInst *arg_ins;
5206
5207                 NEW_ARGLOAD (cfg, arg_ins, 0);
5208                 MONO_ADD_INS (cfg->cbb, arg_ins);
5209                 cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
5210                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, arg_ins->dreg);
5211                 MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, arg_ins->dreg);
5212         }
5213
5214         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5215         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5216
5217         ins_flag = 0;
5218         start_new_bblock = 0;
5219         cfg->cbb = bblock;
5220         while (ip < end) {
5221
5222                 if (cfg->method == method)
5223                         cfg->real_offset = ip - header->code;
5224                 else
5225                         cfg->real_offset = inline_offset;
5226                 cfg->ip = ip;
5227
5228                 context_used = 0;
5229                 
5230                 if (start_new_bblock) {
5231                         bblock->cil_length = ip - bblock->cil_code;
5232                         if (start_new_bblock == 2) {
5233                                 g_assert (ip == tblock->cil_code);
5234                         } else {
5235                                 GET_BBLOCK (cfg, tblock, ip);
5236                         }
5237                         bblock->next_bb = tblock;
5238                         bblock = tblock;
5239                         cfg->cbb = bblock;
5240                         start_new_bblock = 0;
5241                         for (i = 0; i < bblock->in_scount; ++i) {
5242                                 if (cfg->verbose_level > 3)
5243                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5244                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5245                                 *sp++ = ins;
5246                         }
5247                         if (class_inits)
5248                                 g_slist_free (class_inits);
5249                         class_inits = NULL;
5250                 } else {
5251                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5252                                 link_bblock (cfg, bblock, tblock);
5253                                 if (sp != stack_start) {
5254                                         handle_stack_args (cfg, stack_start, sp - stack_start);
5255                                         sp = stack_start;
5256                                         CHECK_UNVERIFIABLE (cfg);
5257                                 }
5258                                 bblock->next_bb = tblock;
5259                                 bblock = tblock;
5260                                 cfg->cbb = bblock;
5261                                 for (i = 0; i < bblock->in_scount; ++i) {
5262                                         if (cfg->verbose_level > 3)
5263                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5264                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5265                                         *sp++ = ins;
5266                                 }
5267                                 g_slist_free (class_inits);
5268                                 class_inits = NULL;
5269                         }
5270                 }
5271
5272                 bblock->real_offset = cfg->real_offset;
5273
5274                 if ((cfg->method == method) && cfg->coverage_info) {
5275                         guint32 cil_offset = ip - header->code;
5276                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5277
5278                         /* TODO: Use an increment here */
5279 #if defined(__i386__)
5280                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
5281                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
5282                         ins->inst_imm = 1;
5283                         MONO_ADD_INS (cfg->cbb, ins);
5284 #else
5285                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5286                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
5287 #endif
5288                 }
5289
5290                 if (cfg->verbose_level > 3)
5291                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5292
5293                 switch (*ip) {
5294                 case CEE_NOP:
5295                 case CEE_BREAK:
5296                         MONO_INST_NEW (cfg, ins, (*ip) == CEE_NOP ? OP_NOP : OP_BREAK);
5297                         ip++;
5298                         MONO_ADD_INS (bblock, ins);
5299                         break;
5300                 case CEE_LDARG_0:
5301                 case CEE_LDARG_1:
5302                 case CEE_LDARG_2:
5303                 case CEE_LDARG_3:
5304                         CHECK_STACK_OVF (1);
5305                         n = (*ip)-CEE_LDARG_0;
5306                         CHECK_ARG (n);
5307                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5308                         ip++;
5309                         *sp++ = ins;
5310                         break;
5311                 case CEE_LDLOC_0:
5312                 case CEE_LDLOC_1:
5313                 case CEE_LDLOC_2:
5314                 case CEE_LDLOC_3:
5315                         CHECK_STACK_OVF (1);
5316                         n = (*ip)-CEE_LDLOC_0;
5317                         CHECK_LOCAL (n);
5318                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5319                         ip++;
5320                         *sp++ = ins;
5321                         break;
5322                 case CEE_STLOC_0:
5323                 case CEE_STLOC_1:
5324                 case CEE_STLOC_2:
5325                 case CEE_STLOC_3: {
5326                         guint32 opcode;
5327
5328                         CHECK_STACK (1);
5329                         n = (*ip)-CEE_STLOC_0;
5330                         CHECK_LOCAL (n);
5331                         --sp;
5332                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5333                                 UNVERIFIED;
5334
5335                         opcode = mono_type_to_regmove (cfg, header->locals [n]);
5336                         if ((opcode == OP_MOVE) && ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
5337                                 /* Optimize reg-reg moves away */
5338                                 /* 
5339                                  * Can't optimize other opcodes, since sp[0] might point to
5340                                  * the last ins of a decomposed opcode.
5341                                  */
5342                                 sp [0]->dreg = (cfg)->locals [n]->dreg;
5343                         } else {
5344                                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
5345                         }
5346                         ++ip;
5347                         inline_costs += 1;
5348                         break;
5349                         }
5350                 case CEE_LDARG_S:
5351                         CHECK_OPSIZE (2);
5352                         CHECK_STACK_OVF (1);
5353                         n = ip [1];
5354                         CHECK_ARG (n);
5355                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5356                         *sp++ = ins;
5357                         ip += 2;
5358                         break;
5359                 case CEE_LDARGA_S:
5360                         CHECK_OPSIZE (2);
5361                         CHECK_STACK_OVF (1);
5362                         n = ip [1];
5363                         CHECK_ARG (n);
5364                         NEW_ARGLOADA (cfg, ins, n);
5365                         MONO_ADD_INS (cfg->cbb, ins);
5366                         *sp++ = ins;
5367                         ip += 2;
5368                         break;
5369                 case CEE_STARG_S:
5370                         CHECK_OPSIZE (2);
5371                         CHECK_STACK (1);
5372                         --sp;
5373                         n = ip [1];
5374                         CHECK_ARG (n);
5375                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5376                                 UNVERIFIED;
5377                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
5378                         ip += 2;
5379                         break;
5380                 case CEE_LDLOC_S:
5381                         CHECK_OPSIZE (2);
5382                         CHECK_STACK_OVF (1);
5383                         n = ip [1];
5384                         CHECK_LOCAL (n);
5385                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5386                         *sp++ = ins;
5387                         ip += 2;
5388                         break;
5389                 case CEE_LDLOCA_S:
5390                         CHECK_OPSIZE (2);
5391                         CHECK_STACK_OVF (1);
5392                         CHECK_LOCAL (ip [1]);
5393
5394                         /*
5395                          * ldloca inhibits many optimizations so try to get rid of it in common
5396                          * cases.
5397                          */
5398                         if (ip + 8 < end && (ip [2] == CEE_PREFIX1) && (ip [3] == CEE_INITOBJ) && ip_in_bb (cfg, bblock, ip + 3)) {
5399                                 gboolean skip = FALSE;
5400
5401                                 /* From the INITOBJ case */
5402                                 token = read32 (ip + 4);
5403                                 klass = mini_get_class (method, token, generic_context);
5404                                 CHECK_TYPELOAD (klass);
5405                                 if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
5406                                         GENERIC_SHARING_FAILURE (CEE_INITOBJ);
5407
5408                                 if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5409                                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [ip [1]]->dreg, NULL);
5410                                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
5411                                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [ip [1]]->dreg, klass);
5412                                 } else {
5413                                         skip = TRUE;
5414                                 }
5415                                         
5416                                 if (!skip) {
5417                                         ip += 2 + 6;
5418                                         inline_costs += 1;
5419                                         break;
5420                                 }
5421                         }
5422
5423                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
5424                         *sp++ = ins;
5425                         ip += 2;
5426                         break;
5427                 case CEE_STLOC_S:
5428                         CHECK_OPSIZE (2);
5429                         CHECK_STACK (1);
5430                         --sp;
5431                         CHECK_LOCAL (ip [1]);
5432                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5433                                 UNVERIFIED;
5434                         EMIT_NEW_LOCSTORE (cfg, ins, ip [1], *sp);
5435                         ip += 2;
5436                         inline_costs += 1;
5437                         break;
5438                 case CEE_LDNULL:
5439                         CHECK_STACK_OVF (1);
5440                         EMIT_NEW_PCONST (cfg, ins, NULL);
5441                         ins->type = STACK_OBJ;
5442                         ++ip;
5443                         *sp++ = ins;
5444                         break;
5445                 case CEE_LDC_I4_M1:
5446                         CHECK_STACK_OVF (1);
5447                         EMIT_NEW_ICONST (cfg, ins, -1);
5448                         ++ip;
5449                         *sp++ = ins;
5450                         break;
5451                 case CEE_LDC_I4_0:
5452                 case CEE_LDC_I4_1:
5453                 case CEE_LDC_I4_2:
5454                 case CEE_LDC_I4_3:
5455                 case CEE_LDC_I4_4:
5456                 case CEE_LDC_I4_5:
5457                 case CEE_LDC_I4_6:
5458                 case CEE_LDC_I4_7:
5459                 case CEE_LDC_I4_8:
5460                         CHECK_STACK_OVF (1);
5461                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5462                         ++ip;
5463                         *sp++ = ins;
5464                         break;
5465                 case CEE_LDC_I4_S:
5466                         CHECK_OPSIZE (2);
5467                         CHECK_STACK_OVF (1);
5468                         ++ip;
5469                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
5470                         ++ip;
5471                         *sp++ = ins;
5472                         break;
5473                 case CEE_LDC_I4:
5474                         CHECK_OPSIZE (5);
5475                         CHECK_STACK_OVF (1);
5476                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5477                         ip += 5;
5478                         *sp++ = ins;
5479                         break;
5480                 case CEE_LDC_I8:
5481                         CHECK_OPSIZE (9);
5482                         CHECK_STACK_OVF (1);
5483                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5484                         ins->type = STACK_I8;
5485                         ins->dreg = alloc_dreg (cfg, STACK_I8);
5486                         ++ip;
5487                         ins->inst_l = (gint64)read64 (ip);
5488                         MONO_ADD_INS (bblock, ins);
5489                         ip += 8;
5490                         *sp++ = ins;
5491                         break;
5492                 case CEE_LDC_R4: {
5493                         float *f;
5494                         /* FIXME: we should really allocate this only late in the compilation process */
5495                         mono_domain_lock (cfg->domain);
5496                         f = mono_mempool_alloc (cfg->domain->mp, sizeof (float));
5497                         mono_domain_unlock (cfg->domain);
5498                         CHECK_OPSIZE (5);
5499                         CHECK_STACK_OVF (1);
5500                         MONO_INST_NEW (cfg, ins, OP_R4CONST);
5501                         ins->type = STACK_R8;
5502                         ins->dreg = alloc_dreg (cfg, STACK_R8);
5503                         ++ip;
5504                         readr4 (ip, f);
5505                         ins->inst_p0 = f;
5506                         MONO_ADD_INS (bblock, ins);
5507                         
5508                         ip += 4;
5509                         *sp++ = ins;                    
5510                         break;
5511                 }
5512                 case CEE_LDC_R8: {
5513                         double *d;
5514                         /* FIXME: we should really allocate this only late in the compilation process */
5515                         mono_domain_lock (cfg->domain);
5516                         d = mono_mempool_alloc (cfg->domain->mp, sizeof (double));
5517                         mono_domain_unlock (cfg->domain);
5518                         CHECK_OPSIZE (9);
5519                         CHECK_STACK_OVF (1);
5520                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
5521                         ins->type = STACK_R8;
5522                         ins->dreg = alloc_dreg (cfg, STACK_R8);
5523                         ++ip;
5524                         readr8 (ip, d);
5525                         ins->inst_p0 = d;
5526                         MONO_ADD_INS (bblock, ins);
5527
5528                         ip += 8;
5529                         *sp++ = ins;                    
5530                         break;
5531                 }
5532                 case CEE_DUP: {
5533                         MonoInst *temp, *store;
5534                         CHECK_STACK (1);
5535                         CHECK_STACK_OVF (1);
5536                         sp--;
5537                         ins = *sp;
5538
5539                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
5540                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
5541
5542                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5543                         *sp++ = ins;
5544
5545                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
5546                         *sp++ = ins;
5547
5548                         ++ip;
5549                         inline_costs += 2;
5550                         break;
5551                 }
5552                 case CEE_POP:
5553                         CHECK_STACK (1);
5554                         ip++;
5555                         --sp;
5556
5557 #ifdef __i386__
5558                         if (sp [0]->type == STACK_R8)
5559                                 /* we need to pop the value from the x86 FP stack */
5560                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
5561 #endif
5562                         break;
5563                 case CEE_JMP: {
5564                         MonoCallInst *call;
5565
5566                         CHECK_OPSIZE (5);
5567                         if (stack_start != sp)
5568                                 UNVERIFIED;
5569                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
5570                         ins = (MonoInst*)call;
5571                         token = read32 (ip + 1);
5572                         /* FIXME: check the signature matches */
5573                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
5574
5575                         if (!cmethod)
5576                                 goto load_error;
5577  
5578                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
5579                                 GENERIC_SHARING_FAILURE (CEE_JMP);
5580
5581                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5582                                 if (check_linkdemand (cfg, method, cmethod))
5583                                         INLINE_FAILURE;
5584                                 CHECK_CFG_EXCEPTION;
5585                         }
5586
5587                         ins->inst_p0 = cmethod;
5588                         MONO_ADD_INS (bblock, ins);
5589                         ip += 5;
5590                         start_new_bblock = 1;
5591
5592                         /* FIXME: */
5593                         cfg->disable_aot = 1;
5594                         break;
5595                 }
5596                 case CEE_CALLI:
5597                 case CEE_CALL:
5598                 case CEE_CALLVIRT: {
5599                         MonoInst *addr = NULL;
5600                         MonoMethodSignature *fsig = NULL;
5601                         int array_rank = 0;
5602                         int virtual = *ip == CEE_CALLVIRT;
5603                         int calli = *ip == CEE_CALLI;
5604                         gboolean pass_imt_from_rgctx = FALSE;
5605                         MonoInst *imt_arg = NULL;
5606                         gboolean pass_vtable = FALSE;
5607                         gboolean pass_mrgctx = FALSE;
5608                         MonoInst *vtable_arg = NULL;
5609                         gboolean check_this = FALSE;
5610
5611                         CHECK_OPSIZE (5);
5612                         token = read32 (ip + 1);
5613
5614                         if (calli) {
5615                                 cmethod = NULL;
5616                                 CHECK_STACK (1);
5617                                 --sp;
5618                                 addr = *sp;
5619                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
5620                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5621                                 else
5622                                         fsig = mono_metadata_parse_signature (image, token);
5623
5624                                 n = fsig->param_count + fsig->hasthis;
5625                         } else {
5626                                 MonoMethod *cil_method;
5627                                 
5628                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
5629                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
5630                                         cil_method = cmethod;
5631                                 } else if (constrained_call) {
5632                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
5633                                 } else {
5634                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
5635                                         cil_method = cmethod;
5636                                 }
5637
5638                                 if (!cmethod)
5639                                         goto load_error;
5640                                 if (!dont_verify && !cfg->skip_visibility) {
5641                                         MonoMethod *target_method = cil_method;
5642                                         if (method->is_inflated) {
5643                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
5644                                         }
5645                                         if (!mono_method_can_access_method (method_definition, target_method) &&
5646                                                 !mono_method_can_access_method (method, cil_method))
5647                                                 METHOD_ACCESS_FAILURE;
5648                                 }
5649
5650                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
5651                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
5652
5653                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
5654                                         /* MS.NET seems to silently convert this to a callvirt */
5655                                         virtual = 1;
5656
5657                                 if (!cmethod->klass->inited)
5658                                         if (!mono_class_init (cmethod->klass))
5659                                                 goto load_error;
5660
5661                                 if (mono_method_signature (cmethod)->pinvoke) {
5662                                         MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5663                                         fsig = mono_method_signature (wrapper);
5664                                 } else if (constrained_call) {
5665                                         fsig = mono_method_signature (cmethod);
5666                                 } else {
5667                                         fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
5668                                 }
5669
5670                                 mono_save_token_info (cfg, image, token, cmethod);
5671
5672                                 n = fsig->param_count + fsig->hasthis;
5673
5674                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
5675                                         if (check_linkdemand (cfg, method, cmethod))
5676                                                 INLINE_FAILURE;
5677                                         CHECK_CFG_EXCEPTION;
5678                                 }
5679
5680                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
5681                                     mini_class_is_system_array (cmethod->klass)) {
5682                                         array_rank = cmethod->klass->rank;
5683                                 }
5684
5685                                 if (cmethod->string_ctor)
5686                                         g_assert_not_reached ();
5687                         }
5688
5689                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
5690                                 UNVERIFIED;
5691
5692                         if (!cfg->generic_sharing_context && cmethod)
5693                                 g_assert (!mono_method_check_context_used (cmethod));
5694
5695                         CHECK_STACK (n);
5696
5697                         //g_assert (!virtual || fsig->hasthis);
5698
5699                         sp -= n;
5700
5701                         if (constrained_call) {
5702                                 /*
5703                                  * We have the `constrained.' prefix opcode.
5704                                  */
5705                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
5706                                         int dreg;
5707
5708                                         /*
5709                                          * The type parameter is instantiated as a valuetype,
5710                                          * but that type doesn't override the method we're
5711                                          * calling, so we need to box `this'.
5712                                          */
5713                                         dreg = alloc_dreg (cfg, STACK_VTYPE);
5714                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADV_MEMBASE, dreg, sp [0]->dreg, 0);
5715                                         ins->klass = constrained_call;
5716                                         sp [0] = handle_box (cfg, ins, constrained_call);
5717                                 } else if (!constrained_call->valuetype) {
5718                                         int dreg = alloc_preg (cfg);
5719
5720                                         /*
5721                                          * The type parameter is instantiated as a reference
5722                                          * type.  We have a managed pointer on the stack, so
5723                                          * we need to dereference it here.
5724                                          */
5725                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
5726                                         ins->type = STACK_OBJ;
5727                                         sp [0] = ins;
5728                                 } else if (cmethod->klass->valuetype)
5729                                         virtual = 0;
5730                                 constrained_call = NULL;
5731                         }
5732
5733                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
5734                                 UNVERIFIED;
5735
5736
5737                         if (cmethod && (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
5738                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
5739                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
5740                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
5741                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
5742
5743                                 /*
5744                                  * Pass vtable iff target method might
5745                                  * be shared, which means that sharing
5746                                  * is enabled for its class and its
5747                                  * context is sharable (and it's not a
5748                                  * generic method).
5749                                  */
5750                                 if (sharing_enabled && context_sharable &&
5751                                                 !mini_method_get_context (cmethod)->method_inst)
5752                                         pass_vtable = TRUE;
5753                         }
5754
5755                         if (cmethod && mini_method_get_context (cmethod) &&
5756                                         mini_method_get_context (cmethod)->method_inst) {
5757                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
5758                                 MonoGenericContext *context = mini_method_get_context (cmethod);
5759                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
5760
5761                                 g_assert (!pass_vtable);
5762
5763                                 if (sharing_enabled && context_sharable)
5764                                         pass_mrgctx = TRUE;
5765                         }
5766
5767                         if (cfg->generic_sharing_context && cmethod) {
5768                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
5769
5770                                 context_used = mono_method_check_context_used (cmethod);
5771
5772                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
5773                                         /* Generic method interface
5774                                            calls are resolved via a
5775                                            helper function and don't
5776                                            need an imt. */
5777                                         if (!cmethod_context || !cmethod_context->method_inst)
5778                                                 pass_imt_from_rgctx = TRUE;
5779                                 }
5780
5781                                 /*
5782                                  * If a shared method calls another
5783                                  * shared method then the caller must
5784                                  * have a generic sharing context
5785                                  * because the magic trampoline
5786                                  * requires it.  FIXME: We shouldn't
5787                                  * have to force the vtable/mrgctx
5788                                  * variable here.  Instead there
5789                                  * should be a flag in the cfg to
5790                                  * request a generic sharing context.
5791                                  */
5792                                 if (context_used && method->flags & METHOD_ATTRIBUTE_STATIC)
5793                                         mono_get_vtable_var (cfg);
5794                         }
5795
5796                         // FIXME:
5797                         if (!cmethod)
5798                                 GENERIC_SHARING_FAILURE (*ip);
5799
5800                         if (pass_vtable) {
5801                                 if (context_used) {
5802                                         MonoInst *rgctx;
5803
5804                                         EMIT_GET_RGCTX (rgctx, context_used);
5805                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, rgctx, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
5806                                 } else {
5807                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
5808
5809                                         CHECK_TYPELOAD (cmethod->klass);
5810                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
5811                                 }
5812                         }
5813
5814                         if (pass_mrgctx) {
5815                                 g_assert (!vtable_arg);
5816
5817                                 if (context_used) {
5818                                         MonoInst *rgctx;
5819
5820                                         EMIT_GET_RGCTX (rgctx, context_used);
5821                                         vtable_arg = emit_get_rgctx_method_rgctx (cfg, context_used, rgctx, cmethod);
5822                                 } else {
5823                                         MonoMethodRuntimeGenericContext *mrgctx;
5824
5825                                         mrgctx = mono_method_lookup_rgctx (mono_class_vtable (cfg->domain, cmethod->klass),
5826                                                 mini_method_get_context (cmethod)->method_inst);
5827
5828                                         EMIT_NEW_PCONST (cfg, vtable_arg, mrgctx);
5829                                 }
5830
5831                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
5832                                                 (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) {
5833                                         if (virtual)
5834                                                 check_this = TRUE;
5835                                         virtual = 0;
5836                                 }
5837                         }
5838
5839                         if (pass_imt_from_rgctx) {
5840                                 MonoInst *rgctx;
5841
5842                                 g_assert (!pass_vtable);
5843                                 g_assert (cmethod);
5844
5845                                 EMIT_GET_RGCTX (rgctx, context_used);
5846                                 imt_arg = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod,
5847                                                                                                  MONO_RGCTX_INFO_METHOD);
5848                         }
5849
5850                         if (check_this) {
5851                                 MonoInst *check;
5852
5853                                 MONO_INST_NEW (cfg, check, OP_CHECK_THIS);
5854                                 check->sreg1 = sp [0]->dreg;
5855                                 MONO_ADD_INS (cfg->cbb, check);
5856                         }
5857
5858                         /* Calling virtual generic methods */
5859                         if (cmethod && virtual && 
5860                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
5861                             !((cmethod->flags & METHOD_ATTRIBUTE_FINAL) && 
5862                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
5863                             mono_method_signature (cmethod)->generic_param_count) {
5864                                 MonoInst *this_temp, *this_arg_temp, *store;
5865                                 MonoInst *iargs [4];
5866
5867                                 g_assert (mono_method_signature (cmethod)->is_inflated);
5868
5869                                 /* Prevent inlining of methods that contain indirect calls */
5870                                 INLINE_FAILURE;
5871
5872                                 this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
5873                                 NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
5874                                 MONO_ADD_INS (bblock, store);
5875  
5876                                 /* FIXME: This should be a managed pointer */
5877                                 this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
5878
5879                                 /* Because of the PCONST below */
5880                                 cfg->disable_aot = TRUE;
5881                                 EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
5882                                 if (context_used) {
5883                                         MonoInst *rgctx;
5884
5885                                         EMIT_GET_RGCTX (rgctx, context_used);
5886                                         iargs [1] = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_METHOD);
5887                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
5888                                         addr = mono_emit_jit_icall (cfg,
5889                                                 mono_helper_compile_generic_method_wo_context, iargs);
5890                                 } else {
5891                                         EMIT_NEW_METHODCONST (cfg, iargs [1], cmethod);
5892                                         EMIT_NEW_PCONST (cfg, iargs [2], mono_method_get_context (cmethod));
5893                                         EMIT_NEW_TEMPLOADA (cfg, iargs [3], this_arg_temp->inst_c0);
5894                                         addr = mono_emit_jit_icall (cfg, mono_helper_compile_generic_method, iargs);
5895                                 }
5896
5897                                 EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
5898
5899                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
5900                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
5901                                         *sp++ = ins;
5902
5903                                 ip += 5;
5904                                 ins_flag = 0;
5905                                 break;
5906                         }
5907
5908                         /* Tail prefix */
5909                         /* FIXME: runtime generic context pointer for jumps? */
5910                         /* FIXME: handle this for generic sharing eventually */
5911                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) &&
5912                                  (mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)))) {
5913                                 MonoCallInst *call;
5914
5915                                 /* FIXME: runtime generic context pointer for jumps? */
5916                                 GENERIC_SHARING_FAILURE (*ip);
5917
5918                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
5919                                 INLINE_FAILURE;
5920
5921                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
5922                                 call->tail_call = TRUE;
5923                                 call->method = cmethod;
5924                                 call->signature = mono_method_signature (cmethod);
5925
5926 #ifdef __x86_64__
5927                                 /* Handle tail calls similarly to calls */
5928                                 call->inst.opcode = OP_TAILCALL;
5929                                 call->args = sp;
5930                                 mono_arch_emit_call (cfg, call);
5931 #else
5932                                 /*
5933                                  * We implement tail calls by storing the actual arguments into the 
5934                                  * argument variables, then emitting a CEE_JMP.
5935                                  */
5936                                 for (i = 0; i < n; ++i) {
5937                                         /* Prevent argument from being register allocated */
5938                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
5939                                         EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
5940                                 }
5941 #endif
5942
5943                                 /* FIXME: */
5944                                 cfg->disable_aot = 1;
5945
5946                                 ins = (MonoInst*)call;
5947                                 ins->inst_p0 = cmethod;
5948                                 ins->inst_p1 = arg_array [0];
5949                                 MONO_ADD_INS (bblock, ins);
5950                                 link_bblock (cfg, bblock, end_bblock);                  
5951                                 start_new_bblock = 1;
5952                                 /* skip CEE_RET as well */
5953                                 ip += 6;
5954                                 ins_flag = 0;
5955                                 break;
5956                         }
5957
5958                         /* Conversion to a JIT intrinsic */
5959                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
5960                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5961                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
5962                                         *sp = ins;
5963                                         sp++;
5964                                 }
5965
5966                                 ip += 5;
5967                                 ins_flag = 0;
5968                                 break;
5969                         }
5970
5971                         /* Inlining */
5972                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
5973                             (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || (cmethod->flags & METHOD_ATTRIBUTE_FINAL)) && 
5974                             mono_method_check_inlining (cfg, cmethod) &&
5975                                  !g_list_find (dont_inline, cmethod)) {
5976                                 int costs;
5977                                 gboolean allways = FALSE;
5978
5979                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5980                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5981                                         /* Prevent inlining of methods that call wrappers */
5982                                         INLINE_FAILURE;
5983                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc);
5984                                         allways = TRUE;
5985                                 }
5986
5987                                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) {
5988                                         ip += 5;
5989                                         cfg->real_offset += 5;
5990                                         bblock = cfg->cbb;
5991
5992                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
5993                                                 /* *sp is already set by inline_method */
5994                                                 sp++;
5995
5996                                         inline_costs += costs;
5997                                         ins_flag = 0;
5998                                         break;
5999                                 }
6000                         }
6001                         
6002                         inline_costs += 10 * num_calls++;
6003
6004                         /* Tail recursion elimination */
6005                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
6006                                 gboolean has_vtargs = FALSE;
6007                                 int i;
6008
6009                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6010                                 INLINE_FAILURE;
6011
6012                                 /* keep it simple */
6013                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6014                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6015                                                 has_vtargs = TRUE;
6016                                 }
6017
6018                                 if (!has_vtargs) {
6019                                         for (i = 0; i < n; ++i)
6020                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6021                                         MONO_INST_NEW (cfg, ins, OP_BR);
6022                                         MONO_ADD_INS (bblock, ins);
6023                                         tblock = start_bblock->out_bb [0];
6024                                         link_bblock (cfg, bblock, tblock);
6025                                         ins->inst_target_bb = tblock;
6026                                         start_new_bblock = 1;
6027
6028                                         /* skip the CEE_RET, too */
6029                                         if (ip_in_bb (cfg, bblock, ip + 5))
6030                                                 ip += 6;
6031                                         else
6032                                                 ip += 5;
6033
6034                                         ins_flag = 0;
6035                                         break;
6036                                 }
6037                         }
6038
6039                         /* Generic sharing */
6040                         /* FIXME: only do this for generic methods if
6041                            they are not shared! */
6042                         if (context_used &&
6043                                         (cmethod->klass->valuetype ||
6044                                         (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst && !pass_mrgctx) ||
6045                                         ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
6046                                                 mono_class_generic_sharing_enabled (cmethod->klass)) ||
6047                                         (!imt_arg && !mono_method_is_generic_sharable_impl (cmethod, TRUE) &&
6048                                                 (!virtual || cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6049                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))))) {
6050                                 MonoInst *rgctx;
6051
6052                                 INLINE_FAILURE;
6053
6054                                 g_assert (cfg->generic_sharing_context && cmethod);
6055                                 g_assert (!addr);
6056
6057                                 /*
6058                                  * We are compiling a call to a
6059                                  * generic method from shared code,
6060                                  * which means that we have to look up
6061                                  * the method in the rgctx and do an
6062                                  * indirect call.
6063                                  */
6064
6065                                 EMIT_GET_RGCTX (rgctx, context_used);
6066                                 addr = emit_get_rgctx_method (cfg, context_used, rgctx, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
6067                         }
6068
6069                         /* Indirect calls */
6070                         if (addr) {
6071                                 g_assert (!imt_arg);
6072
6073                                 if (*ip == CEE_CALL)
6074                                         g_assert (context_used);
6075                                 else if (*ip == CEE_CALLI)
6076                                         g_assert (!vtable_arg);
6077                                 else
6078                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6079                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6080
6081                                 /* Prevent inlining of methods with indirect calls */
6082                                 INLINE_FAILURE;
6083
6084                                 if (vtable_arg) {
6085 #ifdef MONO_ARCH_RGCTX_REG
6086                                         MonoCallInst *call;
6087                                         int rgctx_reg = mono_alloc_preg (cfg);
6088
6089                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
6090                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6091                                         call = (MonoCallInst*)ins;
6092                                         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
6093 #else
6094                                         GENERIC_SHARING_FAILURE (*ip);
6095 #endif
6096                                 } else {
6097                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6098                                 }
6099                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6100                                         if (fsig->pinvoke && !fsig->ret->byref) {
6101                                                 int widen_op = -1;
6102
6103                                                 /* 
6104                                                  * Native code might return non register sized integers 
6105                                                  * without initializing the upper bits.
6106                                                  */
6107                                                 switch (mono_type_to_load_membase (cfg, fsig->ret)) {
6108                                                 case OP_LOADI1_MEMBASE:
6109                                                         widen_op = OP_ICONV_TO_I1;
6110                                                         break;
6111                                                 case OP_LOADU1_MEMBASE:
6112                                                         widen_op = OP_ICONV_TO_U1;
6113                                                         break;
6114                                                 case OP_LOADI2_MEMBASE:
6115                                                         widen_op = OP_ICONV_TO_I2;
6116                                                         break;
6117                                                 case OP_LOADU2_MEMBASE:
6118                                                         widen_op = OP_ICONV_TO_U2;
6119                                                         break;
6120                                                 default:
6121                                                         break;
6122                                                 }
6123
6124                                                 if (widen_op != -1) {
6125                                                         int dreg = alloc_preg (cfg);
6126                                                         MonoInst *widen;
6127
6128                                                         EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
6129                                                         widen->type = ins->type;
6130                                                         ins = widen;
6131                                                 }
6132                                         }
6133
6134                                         *sp++ = ins;
6135                                 }
6136
6137                                 ip += 5;
6138                                 ins_flag = 0;
6139                                 break;
6140                         }
6141                                         
6142                         /* Array methods */
6143                         if (array_rank) {
6144                                 MonoInst *addr;
6145
6146                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6147                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6148                                                 MonoInst *iargs [2];
6149
6150                                                 iargs [0] = sp [0];
6151                                                 iargs [1] = sp [fsig->param_count];
6152                                                 
6153                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
6154                                         }
6155                                         
6156                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
6157                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, sp [fsig->param_count]->dreg);
6158                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6159                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6160
6161                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
6162
6163                                         *sp++ = ins;
6164                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6165                                         if (!cmethod->klass->element_class->valuetype && !readonly)
6166                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
6167                                         
6168                                         readonly = FALSE;
6169                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6170                                         *sp++ = addr;
6171                                 } else {
6172                                         g_assert_not_reached ();
6173                                 }
6174
6175                                 ip += 5;
6176                                 ins_flag = 0;
6177                                 break;
6178                         }
6179
6180                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
6181                         if (ins) {
6182                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6183                                         *sp++ = ins;
6184
6185                                 ip += 5;
6186                                 ins_flag = 0;
6187                                 break;
6188                         }
6189
6190                         /* Common call */
6191                         INLINE_FAILURE;
6192                         if (vtable_arg) {
6193 #ifdef MONO_ARCH_RGCTX_REG
6194                                 MonoCallInst *call;
6195                                 int rgctx_reg = mono_alloc_preg (cfg);
6196
6197                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
6198                                 ins = (MonoInst*)mono_emit_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
6199                                 call = (MonoCallInst*)ins;
6200                                 mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
6201 #else
6202                                 GENERIC_SHARING_FAILURE (*ip);                          
6203 #endif
6204                         } else if (imt_arg) {
6205                                 ins = (MonoInst*)mono_emit_imt_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
6206                         } else {
6207                                 ins = (MonoInst*)mono_emit_method_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
6208                         }
6209
6210                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6211                                 *sp++ = ins;
6212
6213                         ip += 5;
6214                         ins_flag = 0;
6215                         break;
6216                 }
6217                 case CEE_RET:
6218                         if (cfg->method != method) {
6219                                 /* return from inlined method */
6220                                 if (return_var) {
6221                                         MonoInst *store;
6222                                         CHECK_STACK (1);
6223                                         --sp;
6224                                         //g_assert (returnvar != -1);
6225                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6226                                         cfg->ret_var_set = TRUE;
6227                                 } 
6228                         } else {
6229                                 if (cfg->ret) {
6230                                         MonoType *ret_type = mono_method_signature (method)->ret;
6231
6232                                         g_assert (!return_var);
6233                                         CHECK_STACK (1);
6234                                         --sp;
6235                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
6236                                                 MonoInst *ret_addr;
6237
6238                                                 if (!cfg->vret_addr) {
6239                                                         MonoInst *ins;
6240
6241                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
6242                                                 } else {
6243                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
6244
6245                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
6246                                                         ins->klass = mono_class_from_mono_type (ret_type);
6247                                                 }
6248                                         } else {
6249 #ifdef MONO_ARCH_SOFT_FLOAT
6250                                                 if (!ret_type->byref && ret_type->type == MONO_TYPE_R4) {
6251                                                         MonoInst *iargs [1];
6252                                                         MonoInst *conv;
6253
6254                                                         iargs [0] = *sp;
6255                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
6256                                                         mono_arch_emit_setret (cfg, method, conv);
6257                                                 } else {
6258                                                         mono_arch_emit_setret (cfg, method, *sp);
6259                                                 }
6260 #else
6261                                                 mono_arch_emit_setret (cfg, method, *sp);
6262 #endif
6263                                         }
6264                                 }
6265                         }
6266                         if (sp != stack_start)
6267                                 UNVERIFIED;
6268                         MONO_INST_NEW (cfg, ins, OP_BR);
6269                         ip++;
6270                         ins->inst_target_bb = end_bblock;
6271                         MONO_ADD_INS (bblock, ins);
6272                         link_bblock (cfg, bblock, end_bblock);
6273                         start_new_bblock = 1;
6274                         break;
6275                 case CEE_BR_S:
6276                         CHECK_OPSIZE (2);
6277                         MONO_INST_NEW (cfg, ins, OP_BR);
6278                         ip++;
6279                         target = ip + 1 + (signed char)(*ip);
6280                         ++ip;
6281                         GET_BBLOCK (cfg, tblock, target);
6282                         link_bblock (cfg, bblock, tblock);
6283                         CHECK_BBLOCK (target, ip, tblock);
6284                         ins->inst_target_bb = tblock;
6285                         if (sp != stack_start) {
6286                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6287                                 sp = stack_start;
6288                                 CHECK_UNVERIFIABLE (cfg);
6289                         }
6290                         MONO_ADD_INS (bblock, ins);
6291                         start_new_bblock = 1;
6292                         inline_costs += BRANCH_COST;
6293                         break;
6294                 case CEE_BEQ_S:
6295                 case CEE_BGE_S:
6296                 case CEE_BGT_S:
6297                 case CEE_BLE_S:
6298                 case CEE_BLT_S:
6299                 case CEE_BNE_UN_S:
6300                 case CEE_BGE_UN_S:
6301                 case CEE_BGT_UN_S:
6302                 case CEE_BLE_UN_S:
6303                 case CEE_BLT_UN_S:
6304                         CHECK_OPSIZE (2);
6305                         CHECK_STACK (2);
6306                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6307                         ip++;
6308                         target = ip + 1 + *(signed char*)ip;
6309                         ip++;
6310
6311                         ADD_BINCOND (NULL);
6312
6313                         sp = stack_start;
6314                         inline_costs += BRANCH_COST;
6315                         break;
6316                 case CEE_BR:
6317                         CHECK_OPSIZE (5);
6318                         MONO_INST_NEW (cfg, ins, OP_BR);
6319                         ip++;
6320
6321                         target = ip + 4 + (gint32)read32(ip);
6322                         ip += 4;
6323                         GET_BBLOCK (cfg, tblock, target);
6324                         link_bblock (cfg, bblock, tblock);
6325                         CHECK_BBLOCK (target, ip, tblock);
6326                         ins->inst_target_bb = tblock;
6327                         if (sp != stack_start) {
6328                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6329                                 sp = stack_start;
6330                                 CHECK_UNVERIFIABLE (cfg);
6331                         }
6332
6333                         MONO_ADD_INS (bblock, ins);
6334
6335                         start_new_bblock = 1;
6336                         inline_costs += BRANCH_COST;
6337                         break;
6338                 case CEE_BRFALSE_S:
6339                 case CEE_BRTRUE_S:
6340                 case CEE_BRFALSE:
6341                 case CEE_BRTRUE: {
6342                         MonoInst *cmp;
6343                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
6344                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
6345                         guint32 opsize = is_short ? 1 : 4;
6346
6347                         CHECK_OPSIZE (opsize);
6348                         CHECK_STACK (1);
6349                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6350                                 UNVERIFIED;
6351                         ip ++;
6352                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
6353                         ip += opsize;
6354
6355                         sp--;
6356
6357                         GET_BBLOCK (cfg, tblock, target);
6358                         link_bblock (cfg, bblock, tblock);
6359                         CHECK_BBLOCK (target, ip, tblock);
6360                         GET_BBLOCK (cfg, tblock, ip);
6361                         link_bblock (cfg, bblock, tblock);
6362
6363                         if (sp != stack_start) {
6364                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6365                                 CHECK_UNVERIFIABLE (cfg);
6366                         }
6367
6368                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
6369                         cmp->sreg1 = sp [0]->dreg;
6370                         type_from_op (cmp, sp [0], NULL);
6371                         CHECK_TYPE (cmp);
6372
6373 #if SIZEOF_VOID_P == 4
6374                         if (cmp->opcode == OP_LCOMPARE_IMM) {
6375                                 /* Convert it to OP_LCOMPARE */
6376                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6377                                 ins->type = STACK_I8;
6378                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
6379                                 ins->inst_l = 0;
6380                                 MONO_ADD_INS (bblock, ins);
6381                                 cmp->opcode = OP_LCOMPARE;
6382                                 cmp->sreg2 = ins->dreg;
6383                         }
6384 #endif
6385                         MONO_ADD_INS (bblock, cmp);
6386
6387                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
6388                         type_from_op (ins, sp [0], NULL);
6389                         MONO_ADD_INS (bblock, ins);
6390                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
6391                         GET_BBLOCK (cfg, tblock, target);
6392                         ins->inst_true_bb = tblock;
6393                         GET_BBLOCK (cfg, tblock, ip);
6394                         ins->inst_false_bb = tblock;
6395                         start_new_bblock = 2;
6396
6397                         sp = stack_start;
6398                         inline_costs += BRANCH_COST;
6399                         break;
6400                 }
6401                 case CEE_BEQ:
6402                 case CEE_BGE:
6403                 case CEE_BGT:
6404                 case CEE_BLE:
6405                 case CEE_BLT:
6406                 case CEE_BNE_UN:
6407                 case CEE_BGE_UN:
6408                 case CEE_BGT_UN:
6409                 case CEE_BLE_UN:
6410                 case CEE_BLT_UN:
6411                         CHECK_OPSIZE (5);
6412                         CHECK_STACK (2);
6413                         MONO_INST_NEW (cfg, ins, *ip);
6414                         ip++;
6415                         target = ip + 4 + (gint32)read32(ip);
6416                         ip += 4;
6417
6418                         ADD_BINCOND (NULL);
6419
6420                         sp = stack_start;
6421                         inline_costs += BRANCH_COST;
6422                         break;
6423                 case CEE_SWITCH: {
6424                         MonoInst *src1;
6425                         MonoBasicBlock **targets;
6426                         MonoBasicBlock *default_bblock;
6427                         MonoJumpInfoBBTable *table;
6428                         int offset_reg = alloc_preg (cfg);
6429                         int target_reg = alloc_preg (cfg);
6430                         int table_reg = alloc_preg (cfg);
6431                         int sum_reg = alloc_preg (cfg);
6432
6433                         CHECK_OPSIZE (5);
6434                         CHECK_STACK (1);
6435                         n = read32 (ip + 1);
6436                         --sp;
6437                         src1 = sp [0];
6438                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
6439                                 UNVERIFIED;
6440
6441                         ip += 5;
6442                         CHECK_OPSIZE (n * sizeof (guint32));
6443                         target = ip + n * sizeof (guint32);
6444
6445                         GET_BBLOCK (cfg, default_bblock, target);
6446
6447                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
6448                         for (i = 0; i < n; ++i) {
6449                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6450                                 targets [i] = tblock;
6451                                 ip += 4;
6452                         }
6453
6454                         if (sp != stack_start) {
6455                                 /* 
6456                                  * Link the current bb with the targets as well, so handle_stack_args
6457                                  * will set their in_stack correctly.
6458                                  */
6459                                 link_bblock (cfg, bblock, default_bblock);
6460                                 for (i = 0; i < n; ++i)
6461                                         link_bblock (cfg, bblock, targets [i]);
6462
6463                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6464                                 sp = stack_start;
6465                                 CHECK_UNVERIFIABLE (cfg);
6466                         }
6467
6468                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
6469                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
6470                         bblock = cfg->cbb;
6471
6472                         for (i = 0; i < n; ++i)
6473                                 link_bblock (cfg, bblock, targets [i]);
6474
6475                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
6476                         table->table = targets;
6477                         table->table_size = n;
6478
6479 #ifdef __arm__
6480                         /* ARM implements SWITCH statements differently */
6481                         /* FIXME: Make it use the generic implementation */
6482                         /* the backend code will deal with aot vs normal case */
6483                         MONO_INST_NEW (cfg, ins, OP_SWITCH);
6484                         ins->sreg1 = src1->dreg;
6485                         ins->inst_p0 = table;
6486                         ins->inst_many_bb = targets;
6487                         ins->klass = GUINT_TO_POINTER (n);
6488                         MONO_ADD_INS (cfg->cbb, ins);
6489 #else
6490                         if (sizeof (gpointer) == 8)
6491                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
6492                         else
6493                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
6494
6495 #if SIZEOF_VOID_P == 8
6496                         /* The upper word might not be zero, and we add it to a 64 bit address later */
6497                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
6498 #endif
6499
6500                         if (cfg->compile_aot) {
6501                                 MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
6502                         } else {
6503                                 MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
6504                                 ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
6505                                 ins->inst_p0 = table;
6506                                 ins->dreg = table_reg;
6507                                 MONO_ADD_INS (cfg->cbb, ins);
6508                         }
6509
6510                         /* FIXME: Use load_memindex */
6511                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
6512                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
6513                         MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
6514 #endif
6515                         start_new_bblock = 1;
6516                         inline_costs += (BRANCH_COST * 2);
6517                         break;
6518                 }
6519                 case CEE_LDIND_I1:
6520                 case CEE_LDIND_U1:
6521                 case CEE_LDIND_I2:
6522                 case CEE_LDIND_U2:
6523                 case CEE_LDIND_I4:
6524                 case CEE_LDIND_U4:
6525                 case CEE_LDIND_I8:
6526                 case CEE_LDIND_I:
6527                 case CEE_LDIND_R4:
6528                 case CEE_LDIND_R8:
6529                 case CEE_LDIND_REF:
6530                         CHECK_STACK (1);
6531                         --sp;
6532
6533                         switch (*ip) {
6534                         case CEE_LDIND_R4:
6535                         case CEE_LDIND_R8:
6536                                 dreg = alloc_freg (cfg);
6537                                 break;
6538                         case CEE_LDIND_I8:
6539                                 dreg = alloc_lreg (cfg);
6540                                 break;
6541                         default:
6542                                 dreg = alloc_preg (cfg);
6543                         }
6544
6545                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
6546                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
6547                         ins->flags |= ins_flag;
6548                         ins_flag = 0;
6549                         MONO_ADD_INS (bblock, ins);
6550                         *sp++ = ins;
6551                         ++ip;
6552                         break;
6553                 case CEE_STIND_REF:
6554                 case CEE_STIND_I1:
6555                 case CEE_STIND_I2:
6556                 case CEE_STIND_I4:
6557                 case CEE_STIND_I8:
6558                 case CEE_STIND_R4:
6559                 case CEE_STIND_R8:
6560                 case CEE_STIND_I:
6561                         CHECK_STACK (2);
6562                         sp -= 2;
6563
6564                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
6565                         ins->flags |= ins_flag;
6566                         ins_flag = 0;
6567                         MONO_ADD_INS (bblock, ins);
6568                         inline_costs += 1;
6569                         ++ip;
6570                         break;
6571
6572                 case CEE_MUL:
6573                         CHECK_STACK (2);
6574
6575                         MONO_INST_NEW (cfg, ins, (*ip));
6576                         sp -= 2;
6577                         ins->sreg1 = sp [0]->dreg;
6578                         ins->sreg2 = sp [1]->dreg;
6579                         type_from_op (ins, sp [0], sp [1]);
6580                         CHECK_TYPE (ins);
6581                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
6582
6583                         /* Use the immediate opcodes if possible */
6584                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
6585                                 int imm_opcode = mono_op_to_op_imm (ins->opcode);
6586                                 if (imm_opcode != -1) {
6587                                         ins->opcode = imm_opcode;
6588                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
6589                                         ins->sreg2 = -1;
6590
6591                                         sp [1]->opcode = OP_NOP;
6592                                 }
6593                         }
6594
6595                         MONO_ADD_INS ((cfg)->cbb, (ins));
6596                         *sp++ = ins;
6597
6598                         mono_decompose_opcode (cfg, ins);
6599                         ip++;
6600                         break;
6601                 case CEE_ADD:
6602                 case CEE_SUB:
6603                 case CEE_DIV:
6604                 case CEE_DIV_UN:
6605                 case CEE_REM:
6606                 case CEE_REM_UN:
6607                 case CEE_AND:
6608                 case CEE_OR:
6609                 case CEE_XOR:
6610                 case CEE_SHL:
6611                 case CEE_SHR:
6612                 case CEE_SHR_UN:
6613                         CHECK_STACK (2);
6614
6615                         MONO_INST_NEW (cfg, ins, (*ip));
6616                         sp -= 2;
6617                         ins->sreg1 = sp [0]->dreg;
6618                         ins->sreg2 = sp [1]->dreg;
6619                         type_from_op (ins, sp [0], sp [1]);
6620                         CHECK_TYPE (ins);
6621                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
6622                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
6623
6624                         /* FIXME: Pass opcode to is_inst_imm */
6625
6626                         /* Use the immediate opcodes if possible */
6627                         if (((sp [1]->opcode == OP_ICONST) || (sp [1]->opcode == OP_I8CONST)) && mono_arch_is_inst_imm (sp [1]->opcode == OP_ICONST ? sp [1]->inst_c0 : sp [1]->inst_l)) {
6628                                 int imm_opcode;
6629
6630                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
6631                                 if (imm_opcode != -1) {
6632                                         ins->opcode = imm_opcode;
6633                                         if (sp [1]->opcode == OP_I8CONST) {
6634 #if SIZEOF_VOID_P == 8
6635                                                 ins->inst_imm = sp [1]->inst_l;
6636 #else
6637                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
6638                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
6639 #endif
6640                                         }
6641                                         else
6642                                                 ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
6643                                         ins->sreg2 = -1;
6644
6645                                         sp [1]->opcode = OP_NOP;
6646                                 }
6647                         }
6648                         MONO_ADD_INS ((cfg)->cbb, (ins));
6649                         *sp++ = ins;
6650
6651                         mono_decompose_opcode (cfg, ins);
6652                         ip++;
6653                         break;
6654                 case CEE_NEG:
6655                 case CEE_NOT:
6656                 case CEE_CONV_I1:
6657                 case CEE_CONV_I2:
6658                 case CEE_CONV_I4:
6659                 case CEE_CONV_R4:
6660                 case CEE_CONV_R8:
6661                 case CEE_CONV_U4:
6662                 case CEE_CONV_I8:
6663                 case CEE_CONV_U8:
6664                 case CEE_CONV_OVF_I8:
6665                 case CEE_CONV_OVF_U8:
6666                 case CEE_CONV_R_UN:
6667                         CHECK_STACK (1);
6668
6669                         /* Special case this earlier so we have long constants in the IR */
6670                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
6671                                 int data = sp [-1]->inst_c0;
6672                                 sp [-1]->opcode = OP_I8CONST;
6673                                 sp [-1]->type = STACK_I8;
6674 #if SIZEOF_VOID_P == 8
6675                                 if ((*ip) == CEE_CONV_U8)
6676                                         sp [-1]->inst_c0 = (guint32)data;
6677                                 else
6678                                         sp [-1]->inst_c0 = data;
6679 #else
6680                                 sp [-1]->inst_ls_word = data;
6681                                 if ((*ip) == CEE_CONV_U8)
6682                                         sp [-1]->inst_ms_word = 0;
6683                                 else
6684                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
6685 #endif
6686                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
6687                         }
6688                         else {
6689                                 ADD_UNOP (*ip);
6690                         }
6691                         ip++;
6692                         break;
6693                 case CEE_CONV_OVF_I4:
6694                 case CEE_CONV_OVF_I1:
6695                 case CEE_CONV_OVF_I2:
6696                 case CEE_CONV_OVF_I:
6697                 case CEE_CONV_OVF_U:
6698                         CHECK_STACK (1);
6699
6700                         if (sp [-1]->type == STACK_R8) {
6701                                 ADD_UNOP (CEE_CONV_OVF_I8);
6702                                 ADD_UNOP (*ip);
6703                         } else {
6704                                 ADD_UNOP (*ip);
6705                         }
6706                         ip++;
6707                         break;
6708                 case CEE_CONV_OVF_U1:
6709                 case CEE_CONV_OVF_U2:
6710                 case CEE_CONV_OVF_U4:
6711                         CHECK_STACK (1);
6712
6713                         if (sp [-1]->type == STACK_R8) {
6714                                 ADD_UNOP (CEE_CONV_OVF_U8);
6715                                 ADD_UNOP (*ip);
6716                         } else {
6717                                 ADD_UNOP (*ip);
6718                         }
6719                         ip++;
6720                         break;
6721                 case CEE_CONV_OVF_I1_UN:
6722                 case CEE_CONV_OVF_I2_UN:
6723                 case CEE_CONV_OVF_I4_UN:
6724                 case CEE_CONV_OVF_I8_UN:
6725                 case CEE_CONV_OVF_U1_UN:
6726                 case CEE_CONV_OVF_U2_UN:
6727                 case CEE_CONV_OVF_U4_UN:
6728                 case CEE_CONV_OVF_U8_UN:
6729                 case CEE_CONV_OVF_I_UN:
6730                 case CEE_CONV_OVF_U_UN:
6731                 case CEE_CONV_U2:
6732                 case CEE_CONV_U1:
6733                 case CEE_CONV_I:
6734                 case CEE_CONV_U:
6735                         CHECK_STACK (1);
6736                         ADD_UNOP (*ip);
6737                         ip++;
6738                         break;
6739                 case CEE_ADD_OVF:
6740                 case CEE_ADD_OVF_UN:
6741                 case CEE_MUL_OVF:
6742                 case CEE_MUL_OVF_UN:
6743                 case CEE_SUB_OVF:
6744                 case CEE_SUB_OVF_UN:
6745                         CHECK_STACK (2);
6746                         ADD_BINOP (*ip);
6747                         ip++;
6748                         break;
6749                 case CEE_CPOBJ:
6750                         CHECK_OPSIZE (5);
6751                         CHECK_STACK (2);
6752                         token = read32 (ip + 1);
6753                         klass = mini_get_class (method, token, generic_context);
6754                         CHECK_TYPELOAD (klass);
6755                         sp -= 2;
6756                         if (generic_class_is_reference_type (cfg, klass)) {
6757                                 MonoInst *store, *load;
6758                                 int dreg = alloc_preg (cfg);
6759
6760                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
6761                                 load->flags |= ins_flag;
6762                                 MONO_ADD_INS (cfg->cbb, load);
6763
6764                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
6765                                 store->flags |= ins_flag;
6766                                 MONO_ADD_INS (cfg->cbb, store);
6767                         } else {
6768                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
6769                         }
6770                         ins_flag = 0;
6771                         ip += 5;
6772                         break;
6773                 case CEE_LDOBJ: {
6774                         int loc_index = -1;
6775                         int stloc_len = 0;
6776
6777                         CHECK_OPSIZE (5);
6778                         CHECK_STACK (1);
6779                         --sp;
6780                         token = read32 (ip + 1);
6781                         klass = mini_get_class (method, token, generic_context);
6782                         CHECK_TYPELOAD (klass);
6783
6784                         /* Optimize the common ldobj+stloc combination */
6785                         switch (ip [5]) {
6786                         case CEE_STLOC_S:
6787                                 loc_index = ip [6];
6788                                 stloc_len = 2;
6789                                 break;
6790                         case CEE_STLOC_0:
6791                         case CEE_STLOC_1:
6792                         case CEE_STLOC_2:
6793                         case CEE_STLOC_3:
6794                                 loc_index = ip [5] - CEE_STLOC_0;
6795                                 stloc_len = 1;
6796                                 break;
6797                         default:
6798                                 break;
6799                         }
6800
6801                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
6802                                 CHECK_LOCAL (loc_index);
6803
6804                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
6805                                 ins->dreg = cfg->locals [loc_index]->dreg;
6806                                 ip += 5;
6807                                 ip += stloc_len;
6808                                 break;
6809                         }
6810
6811                         /* Optimize the ldobj+stobj combination */
6812                         /* The reference case ends up being a load+store anyway */
6813                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 9) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
6814                                 CHECK_STACK (1);
6815
6816                                 sp --;
6817
6818                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
6819
6820                                 ip += 5 + 5;
6821                                 ins_flag = 0;
6822                                 break;
6823                         }
6824
6825                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
6826                         *sp++ = ins;
6827
6828                         ip += 5;
6829                         ins_flag = 0;
6830                         inline_costs += 1;
6831                         break;
6832                 }
6833                 case CEE_LDSTR:
6834                         CHECK_STACK_OVF (1);
6835                         CHECK_OPSIZE (5);
6836                         n = read32 (ip + 1);
6837
6838                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
6839                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
6840                                 ins->type = STACK_OBJ;
6841                                 *sp = ins;
6842                         }
6843                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
6844                                 MonoInst *iargs [1];
6845
6846                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
6847                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
6848                         } else {
6849                                 if (cfg->opt & MONO_OPT_SHARED) {
6850                                         MonoInst *iargs [3];
6851
6852                                         if (cfg->compile_aot) {
6853                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
6854                                         }
6855                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
6856                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
6857                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
6858                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
6859                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6860                                 } else {
6861                                         if (bblock->out_of_line) {
6862                                                 MonoInst *iargs [2];
6863
6864                                                 if (cfg->method->klass->image == mono_defaults.corlib) {
6865                                                         /* 
6866                                                          * Avoid relocations in AOT and save some space by using a 
6867                                                          * version of helper_ldstr specialized to mscorlib.
6868                                                          */
6869                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
6870                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
6871                                                 } else {
6872                                                         /* Avoid creating the string object */
6873                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
6874                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
6875                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
6876                                                 }
6877                                         } 
6878                                         else
6879                                         if (cfg->compile_aot) {
6880                                                 NEW_LDSTRCONST (cfg, ins, image, n);
6881                                                 *sp = ins;
6882                                                 MONO_ADD_INS (bblock, ins);
6883                                         } 
6884                                         else {
6885                                                 NEW_PCONST (cfg, ins, NULL);
6886                                                 ins->type = STACK_OBJ;
6887                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
6888                                                 *sp = ins;
6889                                                 MONO_ADD_INS (bblock, ins);
6890                                         }
6891                                 }
6892                         }
6893
6894                         sp++;
6895                         ip += 5;
6896                         break;
6897                 case CEE_NEWOBJ: {
6898                         MonoInst *iargs [2];
6899                         MonoMethodSignature *fsig;
6900                         MonoInst this_ins;
6901                         MonoInst *alloc;
6902                         
6903                         CHECK_OPSIZE (5);
6904                         token = read32 (ip + 1);
6905                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6906                         if (!cmethod)
6907                                 goto load_error;
6908                         fsig = mono_method_get_signature (cmethod, image, token);
6909
6910                         mono_save_token_info (cfg, image, token, cmethod);
6911
6912                         if (!mono_class_init (cmethod->klass))
6913                                 goto load_error;
6914
6915                         if (cfg->generic_sharing_context)
6916                                 context_used = mono_method_check_context_used (cmethod);
6917
6918                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6919                                 if (check_linkdemand (cfg, method, cmethod))
6920                                         INLINE_FAILURE;
6921                                 CHECK_CFG_EXCEPTION;
6922                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
6923                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
6924                         }
6925
6926                         n = fsig->param_count;
6927                         CHECK_STACK (n);
6928
6929                         /* 
6930                          * Generate smaller code for the common newobj <exception> instruction in
6931                          * argument checking code.
6932                          */
6933                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib && n <= 2 && 
6934                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
6935                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
6936                                 MonoInst *iargs [3];
6937                                 
6938                                 sp -= n;
6939
6940                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
6941                                 switch (n) {
6942                                 case 0:
6943                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
6944                                         break;
6945                                 case 1:
6946                                         iargs [1] = sp [0];
6947                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
6948                                         break;
6949                                 case 2:
6950                                         iargs [1] = sp [0];
6951                                         iargs [2] = sp [1];
6952                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
6953                                         break;
6954                                 default:
6955                                         g_assert_not_reached ();
6956                                 }
6957
6958                                 ip += 5;
6959                                 inline_costs += 5;
6960                                 break;
6961                         }
6962
6963                         /* move the args to allow room for 'this' in the first position */
6964                         while (n--) {
6965                                 --sp;
6966                                 sp [1] = sp [0];
6967                         }
6968
6969                         /* check_call_signature () requires sp[0] to be set */
6970                         this_ins.type = STACK_OBJ;
6971                         sp [0] = &this_ins;
6972                         if (check_call_signature (cfg, fsig, sp))
6973                                 UNVERIFIED;
6974
6975                         iargs [0] = NULL;
6976
6977                         if (mini_class_is_system_array (cmethod->klass)) {
6978                                 g_assert (!context_used);
6979                                 EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
6980                                 if (fsig->param_count == 2)
6981                                         /* Avoid varargs in the common case */
6982                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
6983                                 else
6984                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
6985                         } else if (cmethod->string_ctor) {
6986                                 g_assert (!context_used);
6987                                 /* we simply pass a null pointer */
6988                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
6989                                 /* now call the string ctor */
6990                                 alloc = mono_emit_method_call (cfg, cmethod, fsig, sp, NULL);
6991                         } else {
6992                                 MonoInst* callvirt_this_arg = NULL;
6993                                 
6994                                 if (cmethod->klass->valuetype) {
6995                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
6996                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
6997                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
6998
6999                                         alloc = NULL;
7000
7001                                         /* 
7002                                          * The code generated by mini_emit_virtual_call () expects
7003                                          * iargs [0] to be a boxed instance, but luckily the vcall
7004                                          * will be transformed into a normal call there.
7005                                          */
7006                                 } else if (context_used) {
7007                                         MonoInst *rgctx, *data;
7008                                         int rgctx_info;
7009
7010                                         EMIT_GET_RGCTX (rgctx, context_used);
7011                                         if (cfg->opt & MONO_OPT_SHARED)
7012                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7013                                         else
7014                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7015                                         data = emit_get_rgctx_klass (cfg, context_used, rgctx, cmethod->klass, rgctx_info);
7016
7017                                         alloc = handle_alloc_from_inst (cfg, cmethod->klass, data, FALSE);
7018                                         *sp = alloc;
7019                                 } else {
7020                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7021
7022                                         CHECK_TYPELOAD (cmethod->klass);
7023
7024                                         /*
7025                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
7026                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
7027                                          * As a workaround, we call class cctors before allocating objects.
7028                                          */
7029                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7030                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7031                                                 mono_emit_native_call (cfg, tramp, 
7032                                                                                            helper_sig_class_init_trampoline,
7033                                                                                            NULL);
7034                                                 if (cfg->verbose_level > 2)
7035                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7036                                                 class_inits = g_slist_prepend (class_inits, vtable);
7037                                         }
7038
7039                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE);
7040                                         *sp = alloc;
7041                                 }
7042
7043                                 if (alloc)
7044                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
7045
7046                                 /* Now call the actual ctor */
7047                                 /* Avoid virtual calls to ctors if possible */
7048                                 if (cmethod->klass->marshalbyref)
7049                                         callvirt_this_arg = sp [0];
7050                                 
7051                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used &&
7052                                     mono_method_check_inlining (cfg, cmethod) &&
7053                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7054                                     !g_list_find (dont_inline, cmethod)) {
7055                                         int costs;
7056
7057                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
7058                                                 cfg->real_offset += 5;
7059                                                 bblock = cfg->cbb;
7060
7061                                                 inline_costs += costs - 5;
7062                                         } else {
7063                                                 INLINE_FAILURE;
7064                                                 mono_emit_method_call (cfg, cmethod, fsig, sp, callvirt_this_arg);
7065                                         }
7066                                 } else if (context_used &&
7067                                                 (cmethod->klass->valuetype ||
7068                                                  !mono_method_is_generic_sharable_impl (cmethod, TRUE))) {
7069                                         MonoInst *rgctx, *cmethod_addr;
7070
7071                                         g_assert (!callvirt_this_arg);
7072
7073                                         EMIT_GET_RGCTX (rgctx, context_used);
7074                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used, rgctx,
7075                                                                                                                   cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7076
7077                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr);
7078                                 } else {
7079                                         INLINE_FAILURE;
7080                                         mono_emit_method_call (cfg, cmethod, fsig, sp, callvirt_this_arg);
7081                                 }
7082                         }
7083
7084                         if (alloc == NULL) {
7085                                 /* Valuetype */
7086                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
7087                                 ins->type = STACK_VTYPE;
7088                                 ins->klass = ins->klass;
7089                                 *sp++= ins;
7090                         }
7091                         else
7092                                 *sp++ = alloc;
7093                         
7094                         ip += 5;
7095                         inline_costs += 5;
7096                         break;
7097                 }
7098                 case CEE_CASTCLASS:
7099                         CHECK_STACK (1);
7100                         --sp;
7101                         CHECK_OPSIZE (5);
7102                         token = read32 (ip + 1);
7103                         klass = mini_get_class (method, token, generic_context);
7104                         CHECK_TYPELOAD (klass);
7105                         if (sp [0]->type != STACK_OBJ)
7106                                 UNVERIFIED;
7107
7108                         if (cfg->generic_sharing_context)
7109                                 context_used = mono_class_check_context_used (klass);
7110
7111                         if (context_used) {
7112                                 MonoInst *rgctx, *args [2];
7113
7114                                 g_assert (!method->klass->valuetype);
7115
7116                                 /* obj */
7117                                 args [0] = *sp;
7118
7119                                 /* klass */
7120                                 EMIT_GET_RGCTX (rgctx, context_used);
7121                                 args [1] = emit_get_rgctx_klass (cfg, context_used, rgctx, klass,
7122                                                                                                  MONO_RGCTX_INFO_KLASS);
7123
7124                                 ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
7125                                 *sp ++ = ins;
7126                                 ip += 5;
7127                                 inline_costs += 2;
7128                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7129                                 MonoMethod *mono_castclass;
7130                                 MonoInst *iargs [1];
7131                                 int costs;
7132
7133                                 mono_castclass = mono_marshal_get_castclass (klass); 
7134                                 iargs [0] = sp [0];
7135                                 
7136                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7137                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7138                                 g_assert (costs > 0);
7139                                 
7140                                 ip += 5;
7141                                 cfg->real_offset += 5;
7142                                 bblock = cfg->cbb;
7143
7144                                 *sp++ = iargs [0];
7145
7146                                 inline_costs += costs;
7147                         }
7148                         else {
7149                                 ins = handle_castclass (cfg, klass, *sp);
7150                                 bblock = cfg->cbb;
7151                                 *sp ++ = ins;
7152                                 ip += 5;
7153                         }
7154                         break;
7155                 case CEE_ISINST:
7156                         CHECK_STACK (1);
7157                         --sp;
7158                         CHECK_OPSIZE (5);
7159                         token = read32 (ip + 1);
7160                         klass = mini_get_class (method, token, generic_context);
7161                         CHECK_TYPELOAD (klass);
7162                         if (sp [0]->type != STACK_OBJ)
7163                                 UNVERIFIED;
7164  
7165                         if (cfg->generic_sharing_context && mono_class_check_context_used (klass))
7166                                 GENERIC_SHARING_FAILURE (CEE_ISINST);
7167
7168                         if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7169                         
7170                                 MonoMethod *mono_isinst;
7171                                 MonoInst *iargs [1];
7172                                 int costs;
7173
7174                                 mono_isinst = mono_marshal_get_isinst (klass); 
7175                                 iargs [0] = sp [0];
7176
7177                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
7178                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7179                                 g_assert (costs > 0);
7180                                 
7181                                 ip += 5;
7182                                 cfg->real_offset += 5;
7183                                 bblock = cfg->cbb;
7184
7185                                 *sp++= iargs [0];
7186
7187                                 inline_costs += costs;
7188                         }
7189                         else {
7190                                 ins = handle_isinst (cfg, klass, *sp);
7191                                 bblock = cfg->cbb;
7192                                 *sp ++ = ins;
7193                                 ip += 5;
7194                         }
7195                         break;
7196                 case CEE_UNBOX_ANY: {
7197                         MonoInst *rgctx = NULL;
7198
7199                         CHECK_STACK (1);
7200                         --sp;
7201                         CHECK_OPSIZE (5);
7202                         token = read32 (ip + 1);
7203                         klass = mini_get_class (method, token, generic_context);
7204                         CHECK_TYPELOAD (klass);
7205  
7206                         if (cfg->generic_sharing_context)
7207                                 context_used = mono_class_check_context_used (klass);
7208
7209                         if (generic_class_is_reference_type (cfg, klass)) {
7210                                 /* CASTCLASS */
7211                                 if (context_used) {
7212                                         MonoInst *iargs [2];
7213
7214                                         g_assert (!method->klass->valuetype);
7215
7216                                         /* obj */
7217                                         iargs [0] = *sp;
7218                                         /* klass */
7219                                         EMIT_GET_RGCTX (rgctx, context_used);
7220                                         iargs [1] = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
7221                                         ins = mono_emit_jit_icall (cfg, mono_object_castclass, iargs);
7222                                         *sp ++ = ins;
7223                                         ip += 5;
7224                                         inline_costs += 2;
7225                                 } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                            
7226                                         MonoMethod *mono_castclass;
7227                                         MonoInst *iargs [1];
7228                                         int costs;
7229
7230                                         mono_castclass = mono_marshal_get_castclass (klass); 
7231                                         iargs [0] = sp [0];
7232
7233                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7234                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
7235                         
7236                                         g_assert (costs > 0);
7237                                 
7238                                         ip += 5;
7239                                         cfg->real_offset += 5;
7240                                         bblock = cfg->cbb;
7241
7242                                         *sp++ = iargs [0];
7243                                         inline_costs += costs;
7244                                 } else {
7245                                         ins = handle_castclass (cfg, klass, *sp);
7246                                         bblock = cfg->cbb;
7247                                         *sp ++ = ins;
7248                                         ip += 5;
7249                                 }
7250                                 break;
7251                         }
7252
7253                         if (context_used)
7254                                 EMIT_GET_RGCTX (rgctx, context_used);
7255
7256                         if (mono_class_is_nullable (klass)) {
7257                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used, rgctx);
7258                                 *sp++= ins;
7259                                 ip += 5;
7260                                 break;
7261                         }
7262
7263                         /* UNBOX */
7264                         ins = handle_unbox (cfg, klass, sp, context_used, rgctx);
7265                         *sp = ins;
7266
7267                         ip += 5;
7268
7269                         /* LDOBJ */
7270                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7271                         *sp++ = ins;
7272
7273                         inline_costs += 2;
7274                         break;
7275                 }
7276                 case CEE_BOX: {
7277                         MonoInst *val;
7278                         int context_used = 0;
7279
7280                         CHECK_STACK (1);
7281                         --sp;
7282                         val = *sp;
7283                         CHECK_OPSIZE (5);
7284                         token = read32 (ip + 1);
7285                         klass = mini_get_class (method, token, generic_context);
7286                         CHECK_TYPELOAD (klass);
7287
7288                         if (cfg->generic_sharing_context) {
7289                                 context_used = mono_class_check_context_used (klass);
7290
7291                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
7292                                         GENERIC_SHARING_FAILURE (*ip);
7293                         }
7294
7295                         if (generic_class_is_reference_type (cfg, klass)) {
7296                                 *sp++ = val;
7297                                 ip += 5;
7298                                 break;
7299                         }
7300
7301                         if (klass == mono_defaults.void_class)
7302                                 UNVERIFIED;
7303                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7304                                 UNVERIFIED;
7305                         /* frequent check in generic code: box (struct), brtrue */
7306                         if (!mono_class_is_nullable (klass) &&
7307                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7308                                 /*printf ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7309                                 ip += 5;
7310                                 MONO_INST_NEW (cfg, ins, OP_BR);
7311                                 if (*ip == CEE_BRTRUE_S) {
7312                                         CHECK_OPSIZE (2);
7313                                         ip++;
7314                                         target = ip + 1 + (signed char)(*ip);
7315                                         ip++;
7316                                 } else {
7317                                         CHECK_OPSIZE (5);
7318                                         ip++;
7319                                         target = ip + 4 + (gint)(read32 (ip));
7320                                         ip += 4;
7321                                 }
7322                                 GET_BBLOCK (cfg, tblock, target);
7323                                 link_bblock (cfg, bblock, tblock);
7324                                 CHECK_BBLOCK (target, ip, tblock);
7325                                 ins->inst_target_bb = tblock;
7326                                 GET_BBLOCK (cfg, tblock, ip);
7327                                 link_bblock (cfg, bblock, tblock);
7328                                 if (sp != stack_start) {
7329                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7330                                         sp = stack_start;
7331                                         CHECK_UNVERIFIABLE (cfg);
7332                                 }
7333                                 MONO_ADD_INS (bblock, ins);
7334                                 start_new_bblock = 1;
7335                                 break;
7336                         }
7337
7338                         if (context_used) {
7339                                 MonoInst *rgctx;
7340
7341                                 if (mono_class_is_nullable (klass)) {
7342                                         GENERIC_SHARING_FAILURE (CEE_BOX);
7343                                 } else {
7344                                         MonoInst *data;
7345                                         int rgctx_info;
7346
7347                                         EMIT_GET_RGCTX (rgctx, context_used);
7348                                         if (cfg->opt & MONO_OPT_SHARED)
7349                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7350                                         else
7351                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7352                                         data = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, rgctx_info);
7353                                         *sp++ = handle_box_from_inst (cfg, val, klass, data);
7354                                 }
7355                         } else {
7356                                 *sp++ = handle_box (cfg, val, klass);
7357                         }
7358
7359                         ip += 5;
7360                         inline_costs += 1;
7361                         break;
7362                 }
7363                 case CEE_UNBOX: {
7364                         MonoInst *rgctx = NULL;
7365
7366                         CHECK_STACK (1);
7367                         --sp;
7368                         CHECK_OPSIZE (5);
7369                         token = read32 (ip + 1);
7370                         klass = mini_get_class (method, token, generic_context);
7371                         CHECK_TYPELOAD (klass);
7372
7373                         if (cfg->generic_sharing_context)
7374                                 context_used = mono_class_check_context_used (klass);
7375
7376                         if (context_used)
7377                                 EMIT_GET_RGCTX (rgctx, context_used);
7378  
7379                         if (mono_class_is_nullable (klass)) {
7380                                 MonoInst *val;
7381
7382                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used, rgctx);
7383                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
7384
7385                                 *sp++= ins;
7386                         } else {
7387                                 ins = handle_unbox (cfg, klass, sp, context_used, rgctx);
7388                                 *sp++ = ins;
7389                         }
7390                         ip += 5;
7391                         inline_costs += 2;
7392                         break;
7393                 }
7394                 case CEE_LDFLD:
7395                 case CEE_LDFLDA:
7396                 case CEE_STFLD: {
7397                         MonoClassField *field;
7398                         int costs;
7399                         guint foffset;
7400
7401                         if (*ip == CEE_STFLD) {
7402                                 CHECK_STACK (2);
7403                                 sp -= 2;
7404                         } else {
7405                                 CHECK_STACK (1);
7406                                 --sp;
7407                         }
7408                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7409                                 UNVERIFIED;
7410                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7411                                 UNVERIFIED;
7412                         CHECK_OPSIZE (5);
7413                         token = read32 (ip + 1);
7414                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7415                                 field = mono_method_get_wrapper_data (method, token);
7416                                 klass = field->parent;
7417                         }
7418                         else {
7419                                 field = mono_field_from_token (image, token, &klass, generic_context);
7420                         }
7421                         if (!field)
7422                                 goto load_error;
7423                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7424                                 FIELD_ACCESS_FAILURE;
7425                         mono_class_init (klass);
7426
7427                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
7428                         if (*ip == CEE_STFLD) {
7429                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
7430                                         UNVERIFIED;
7431                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7432                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
7433                                         MonoInst *iargs [5];
7434
7435                                         iargs [0] = sp [0];
7436                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
7437                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
7438                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
7439                                                     field->offset);
7440                                         iargs [4] = sp [1];
7441
7442                                         if (cfg->opt & MONO_OPT_INLINE) {
7443                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
7444                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
7445                                                 g_assert (costs > 0);
7446                                                       
7447                                                 ip += 5;
7448                                                 cfg->real_offset += 5;
7449                                                 bblock = cfg->cbb;
7450
7451                                                 inline_costs += costs;
7452                                                 break;
7453                                         } else {
7454                                                 mono_emit_method_call (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), iargs, NULL);
7455                                         }
7456                                 } else {
7457                                         MonoInst *store;
7458
7459                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
7460                                                 
7461                                         store->flags |= ins_flag;
7462                                         ins_flag = 0;
7463                                 }
7464                                 ip += 5;
7465                                 break;
7466                         }
7467
7468                         if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
7469                                 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
7470                                 MonoInst *iargs [4];
7471
7472                                 iargs [0] = sp [0];
7473                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
7474                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
7475                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
7476                                 if ((cfg->opt & MONO_OPT_INLINE) && !MONO_TYPE_ISSTRUCT (mono_method_signature (wrapper)->ret)) {
7477                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
7478                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
7479                                         bblock = cfg->cbb;
7480                                         g_assert (costs > 0);
7481                                                       
7482                                         ip += 5;
7483                                         cfg->real_offset += 5;
7484
7485                                         *sp++ = iargs [0];
7486
7487                                         inline_costs += costs;
7488                                         break;
7489                                 } else {
7490                                         ins = mono_emit_method_call (cfg, wrapper, mono_method_signature (wrapper), iargs, NULL);
7491                                         *sp++ = ins;
7492                                 }
7493                         } else {
7494                                 if (sp [0]->type == STACK_VTYPE) {
7495                                         MonoInst *var;
7496
7497                                         /* Have to compute the address of the variable */
7498
7499                                         var = cfg->vreg_to_inst [sp [0]->dreg];
7500                                         if (!var && sp [0]->opcode == OP_VMOVE)
7501                                                 var = cfg->vreg_to_inst [sp [0]->sreg1];
7502                                         g_assert (var);
7503                                         
7504                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
7505                                         sp [0] = ins;
7506                                 }
7507
7508                                 if (*ip == CEE_LDFLDA) {
7509                                         dreg = alloc_preg (cfg);
7510
7511                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
7512                                         ins->klass = mono_class_from_mono_type (field->type);
7513                                         ins->type = STACK_MP;
7514                                         *sp++ = ins;
7515                                 } else {
7516                                         MonoInst *load;
7517
7518                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
7519                                         load->flags |= ins_flag;
7520                                         ins_flag = 0;
7521                                         *sp++ = load;
7522                                 }
7523                         }
7524                         ip += 5;
7525                         break;
7526                 }
7527                 case CEE_LDSFLD:
7528                 case CEE_LDSFLDA:
7529                 case CEE_STSFLD: {
7530                         MonoClassField *field;
7531                         gpointer addr = NULL;
7532                         gboolean is_special_static;
7533
7534                         CHECK_OPSIZE (5);
7535                         token = read32 (ip + 1);
7536
7537                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7538                                 field = mono_method_get_wrapper_data (method, token);
7539                                 klass = field->parent;
7540                         }
7541                         else
7542                                 field = mono_field_from_token (image, token, &klass, generic_context);
7543                         if (!field)
7544                                 goto load_error;
7545                         mono_class_init (klass);
7546                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7547                                 FIELD_ACCESS_FAILURE;
7548
7549                         /*
7550                          * We can only support shared generic static
7551                          * field access on architectures where the
7552                          * trampoline code has been extended to handle
7553                          * the generic class init.
7554                          */
7555 #ifndef MONO_ARCH_VTABLE_REG
7556                         GENERIC_SHARING_FAILURE (*ip);
7557 #endif
7558
7559                         if (cfg->generic_sharing_context)
7560                                 context_used = mono_class_check_context_used (klass);
7561
7562                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
7563
7564                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
7565                          * to be called here.
7566                          */
7567                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
7568                                 mono_class_vtable (cfg->domain, klass);
7569                                 CHECK_TYPELOAD (klass);
7570                         }
7571                         mono_domain_lock (cfg->domain);
7572                         if (cfg->domain->special_static_fields)
7573                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
7574                         mono_domain_unlock (cfg->domain);
7575
7576                         is_special_static = mono_class_field_is_special_static (field);
7577
7578                         /* Generate IR to compute the field address */
7579
7580                         if ((cfg->opt & MONO_OPT_SHARED) ||
7581                                         (cfg->compile_aot && is_special_static) ||
7582                                         (context_used && is_special_static)) {
7583                                 MonoInst *iargs [2];
7584
7585                                 g_assert (field->parent);
7586                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7587                                 if (context_used) {
7588                                         MonoInst *rgctx;
7589
7590                                         EMIT_GET_RGCTX (rgctx, context_used);
7591                                         iargs [1] = emit_get_rgctx_field (cfg, context_used, rgctx, field, MONO_RGCTX_INFO_CLASS_FIELD);
7592                                 } else {
7593                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
7594                                 }
7595                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
7596                         } else if (context_used) {
7597                                 MonoInst *rgctx, *static_data;
7598
7599                                 /*
7600                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
7601                                         method->klass->name_space, method->klass->name, method->name,
7602                                         depth, field->offset);
7603                                 */
7604
7605                                 if (mono_class_needs_cctor_run (klass, method)) {
7606                                         MonoCallInst *call;
7607                                         MonoInst *vtable, *rgctx;
7608
7609                                         EMIT_GET_RGCTX (rgctx, context_used);
7610                                         vtable = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_VTABLE);
7611
7612                                         // FIXME: This doesn't work since it tries to pass the argument
7613                                         // in the normal way, instead of using MONO_ARCH_VTABLE_REG
7614                                         /* 
7615                                          * The vtable pointer is always passed in a register regardless of
7616                                          * the calling convention, so assign it manually, and make a call
7617                                          * using a signature without parameters.
7618                                          */                                     
7619                                         call = (MonoCallInst*)mono_emit_native_call (cfg, mono_get_trampoline_code (MONO_TRAMPOLINE_GENERIC_CLASS_INIT), helper_sig_generic_class_init_trampoline, &vtable);
7620 #ifdef MONO_ARCH_VTABLE_REG
7621                                         mono_call_inst_add_outarg_reg (cfg, call, vtable->dreg, MONO_ARCH_VTABLE_REG, FALSE);
7622 #else
7623                                         NOT_IMPLEMENTED;
7624 #endif
7625                                 }
7626
7627                                 /*
7628                                  * The pointer we're computing here is
7629                                  *
7630                                  *   super_info.static_data + field->offset
7631                                  */
7632                                 EMIT_GET_RGCTX (rgctx, context_used);
7633                                 static_data = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_STATIC_DATA);
7634
7635                                 if (field->offset == 0) {
7636                                         ins = static_data;
7637                                 } else {
7638                                         int addr_reg = mono_alloc_preg (cfg);
7639                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
7640                                 }
7641                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
7642                                 MonoInst *iargs [2];
7643
7644                                 g_assert (field->parent);
7645                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7646                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
7647                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
7648                         } else {
7649                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
7650
7651                                 CHECK_TYPELOAD (klass);
7652                                 if (!addr) {
7653                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7654                                                 guint8 *tramp = mono_create_class_init_trampoline (vtable);
7655                                                 mono_emit_native_call (cfg, tramp, 
7656                                                                                            helper_sig_class_init_trampoline,
7657                                                                                            NULL);
7658                                                 if (cfg->verbose_level > 2)
7659                                                         printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, field->name);
7660                                                 class_inits = g_slist_prepend (class_inits, vtable);
7661                                         } else {
7662                                                 if (cfg->run_cctors) {
7663                                                         MonoException *ex;
7664                                                         /* This makes so that inline cannot trigger */
7665                                                         /* .cctors: too many apps depend on them */
7666                                                         /* running with a specific order... */
7667                                                         if (! vtable->initialized)
7668                                                                 INLINE_FAILURE;
7669                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
7670                                                         if (ex) {
7671                                                                 set_exception_object (cfg, ex);
7672                                                                 goto exception_exit;
7673                                                         }
7674                                                 }
7675                                         }
7676                                         addr = (char*)vtable->data + field->offset;
7677
7678                                         if (cfg->compile_aot)
7679                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
7680                                         else
7681                                                 EMIT_NEW_PCONST (cfg, ins, addr);
7682                                 } else {
7683                                         /* 
7684                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
7685                                          * This could be later optimized to do just a couple of
7686                                          * memory dereferences with constant offsets.
7687                                          */
7688                                         MonoInst *iargs [1];
7689                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
7690                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
7691                                 }
7692                         }
7693
7694                         /* Generate IR to do the actual load/store operation */
7695
7696                         if (*ip == CEE_LDSFLDA) {
7697                                 ins->klass = mono_class_from_mono_type (field->type);
7698                                 *sp++ = ins;
7699                         } else if (*ip == CEE_STSFLD) {
7700                                 MonoInst *store;
7701                                 CHECK_STACK (1);
7702                                 sp--;
7703
7704                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, ins->dreg, 0, sp [0]->dreg);
7705                                 store->flags |= ins_flag;
7706                                 ins_flag = 0;
7707                         } else {
7708                                 gboolean is_const = FALSE;
7709                                 MonoVTable *vtable = NULL;
7710
7711                                 if (!context_used) {
7712                                         vtable = mono_class_vtable (cfg->domain, klass);
7713                                         CHECK_TYPELOAD (klass);
7714                                 }
7715                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
7716                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
7717                                         gpointer addr = (char*)vtable->data + field->offset;
7718                                         int ro_type = field->type->type;
7719                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
7720                                                 ro_type = field->type->data.klass->enum_basetype->type;
7721                                         }
7722                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, field->name);*/
7723                                         is_const = TRUE;
7724                                         switch (ro_type) {
7725                                         case MONO_TYPE_BOOLEAN:
7726                                         case MONO_TYPE_U1:
7727                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
7728                                                 sp++;
7729                                                 break;
7730                                         case MONO_TYPE_I1:
7731                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
7732                                                 sp++;
7733                                                 break;                                          
7734                                         case MONO_TYPE_CHAR:
7735                                         case MONO_TYPE_U2:
7736                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
7737                                                 sp++;
7738                                                 break;
7739                                         case MONO_TYPE_I2:
7740                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
7741                                                 sp++;
7742                                                 break;
7743                                                 break;
7744                                         case MONO_TYPE_I4:
7745                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
7746                                                 sp++;
7747                                                 break;                                          
7748                                         case MONO_TYPE_U4:
7749                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
7750                                                 sp++;
7751                                                 break;
7752                                         case MONO_TYPE_I:
7753                                         case MONO_TYPE_U:
7754                                         case MONO_TYPE_STRING:
7755                                         case MONO_TYPE_OBJECT:
7756                                         case MONO_TYPE_CLASS:
7757                                         case MONO_TYPE_SZARRAY:
7758                                         case MONO_TYPE_PTR:
7759                                         case MONO_TYPE_FNPTR:
7760                                         case MONO_TYPE_ARRAY:
7761                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
7762                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
7763                                                 sp++;
7764                                                 break;
7765                                         case MONO_TYPE_I8:
7766                                         case MONO_TYPE_U8:
7767                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
7768                                                 sp++;
7769                                                 break;
7770                                         case MONO_TYPE_R4:
7771                                         case MONO_TYPE_R8:
7772                                         case MONO_TYPE_VALUETYPE:
7773                                         default:
7774                                                 is_const = FALSE;
7775                                                 break;
7776                                         }
7777                                 }
7778
7779                                 if (!is_const) {
7780                                         MonoInst *load;
7781
7782                                         CHECK_STACK_OVF (1);
7783
7784                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
7785                                         load->flags |= ins_flag;
7786                                         ins_flag = 0;
7787                                         *sp++ = load;
7788
7789                                         /* fixme: dont see the problem why this does not work */
7790                                         //cfg->disable_aot = TRUE;
7791                                 }
7792                         }
7793                         ip += 5;
7794                         break;
7795                 }
7796                 case CEE_STOBJ:
7797                         CHECK_STACK (2);
7798                         sp -= 2;
7799                         CHECK_OPSIZE (5);
7800                         token = read32 (ip + 1);
7801                         klass = mini_get_class (method, token, generic_context);
7802                         CHECK_TYPELOAD (klass);
7803                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
7804                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
7805                         ins_flag = 0;
7806                         ip += 5;
7807                         inline_costs += 1;
7808                         break;
7809
7810                         /*
7811                          * Array opcodes
7812                          */
7813                 case CEE_NEWARR: {
7814                         MonoInst *len_ins;
7815                         const char *data_ptr;
7816                         int data_size = 0;
7817                         gboolean shared_access = FALSE;
7818
7819                         CHECK_STACK (1);
7820                         --sp;
7821
7822                         CHECK_OPSIZE (5);
7823                         token = read32 (ip + 1);
7824
7825                         klass = mini_get_class (method, token, generic_context);
7826                         CHECK_TYPELOAD (klass);
7827
7828                         if (cfg->generic_sharing_context) {
7829                                 int context_used = mono_class_check_context_used (klass);
7830
7831                                 if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD)
7832                                         GENERIC_SHARING_FAILURE (CEE_NEWARR);
7833
7834                                 if (context_used)
7835                                         shared_access = TRUE;
7836                         }
7837
7838                         if (shared_access) {
7839                                 MonoInst *rgctx;
7840                                 MonoInst *args [3];
7841
7842                                 /* FIXME: Decompose later to help abcrem */
7843
7844                                 /* domain */
7845                                 EMIT_NEW_DOMAINCONST (cfg, args [0]);
7846
7847                                 /* klass */
7848                                 EMIT_GET_RGCTX (rgctx, context_used);
7849                                 args [1] = emit_get_rgctx_klass (cfg, context_used, rgctx, klass, MONO_RGCTX_INFO_KLASS);
7850
7851                                 /* array len */
7852                                 args [2] = sp [0];
7853
7854                                 ins = mono_emit_jit_icall (cfg, mono_array_new, args);
7855                         } else {
7856                                 if (cfg->opt & MONO_OPT_SHARED) {
7857                                         /* Decompose now to avoid problems with references to the domainvar */
7858                                         MonoInst *iargs [3];
7859
7860                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7861                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
7862                                         iargs [2] = sp [0];
7863
7864                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
7865                                 } else {
7866                                         /* Decompose later since it is needed by abcrem */
7867                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
7868                                         ins->dreg = alloc_preg (cfg);
7869                                         ins->sreg1 = sp [0]->dreg;
7870                                         ins->inst_newa_class = klass;
7871                                         ins->type = STACK_OBJ;
7872                                         ins->klass = klass;
7873                                         MONO_ADD_INS (cfg->cbb, ins);
7874                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
7875                                         cfg->cbb->has_array_access = TRUE;
7876                                 }
7877                         }
7878
7879                         len_ins = sp [0];
7880                         ip += 5;
7881                         *sp++ = ins;
7882                         inline_costs += 1;
7883
7884                         /* 
7885                          * we inline/optimize the initialization sequence if possible.
7886                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
7887                          * for small sizes open code the memcpy
7888                          * ensure the rva field is big enough
7889                          */
7890                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size))) {
7891                                 MonoMethod *memcpy_method = get_memcpy_method ();
7892                                 MonoInst *iargs [3];
7893                                 int add_reg = alloc_preg (cfg);
7894
7895                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
7896                                 if (cfg->compile_aot) {
7897                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(data_ptr), STACK_PTR, NULL);
7898                                 } else {
7899                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
7900                                 }
7901                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
7902                                 mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
7903                                 ip += 11;
7904                         }
7905
7906                         break;
7907                 }
7908                 case CEE_LDLEN:
7909                         CHECK_STACK (1);
7910                         --sp;
7911                         if (sp [0]->type != STACK_OBJ)
7912                                 UNVERIFIED;
7913
7914                         dreg = alloc_preg (cfg);
7915                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
7916                         ins->dreg = alloc_preg (cfg);
7917                         ins->sreg1 = sp [0]->dreg;
7918                         ins->type = STACK_I4;
7919                         MONO_ADD_INS (cfg->cbb, ins);
7920                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
7921                         cfg->cbb->has_array_access = TRUE;
7922                         ip ++;
7923                         *sp++ = ins;
7924                         break;
7925                 case CEE_LDELEMA:
7926                         CHECK_STACK (2);
7927                         sp -= 2;
7928                         CHECK_OPSIZE (5);
7929                         if (sp [0]->type != STACK_OBJ)
7930                                 UNVERIFIED;
7931
7932                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
7933
7934                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
7935                         CHECK_TYPELOAD (klass);
7936                         /* we need to make sure that this array is exactly the type it needs
7937                          * to be for correctness. the wrappers are lax with their usage
7938                          * so we need to ignore them here
7939                          */
7940                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly)
7941                                 mini_emit_check_array_type (cfg, sp [0], mono_array_class_get (klass, 1));
7942
7943                         readonly = FALSE;
7944                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
7945                         *sp++ = ins;
7946                         ip += 5;
7947                         break;
7948                 case CEE_LDELEM_ANY:
7949                 case CEE_LDELEM_I1:
7950                 case CEE_LDELEM_U1:
7951                 case CEE_LDELEM_I2:
7952                 case CEE_LDELEM_U2:
7953                 case CEE_LDELEM_I4:
7954                 case CEE_LDELEM_U4:
7955                 case CEE_LDELEM_I8:
7956                 case CEE_LDELEM_I:
7957                 case CEE_LDELEM_R4:
7958                 case CEE_LDELEM_R8:
7959                 case CEE_LDELEM_REF: {
7960                         MonoInst *addr;
7961
7962                         CHECK_STACK (2);
7963                         sp -= 2;
7964
7965                         if (*ip == CEE_LDELEM_ANY) {
7966                                 CHECK_OPSIZE (5);
7967                                 token = read32 (ip + 1);
7968                                 klass = mini_get_class (method, token, generic_context);
7969                                 CHECK_TYPELOAD (klass);
7970                                 mono_class_init (klass);
7971                         }
7972                         else
7973                                 klass = array_access_to_klass (*ip);
7974
7975                         if (sp [0]->type != STACK_OBJ)
7976                                 UNVERIFIED;
7977
7978                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
7979
7980                         if (sp [1]->opcode == OP_ICONST) {
7981                                 int array_reg = sp [0]->dreg;
7982                                 int index_reg = sp [1]->dreg;
7983                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
7984
7985                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
7986                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
7987                         } else {
7988                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
7989                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
7990                         }
7991                         *sp++ = ins;
7992                         if (*ip == CEE_LDELEM_ANY)
7993                                 ip += 5;
7994                         else
7995                                 ++ip;
7996                         break;
7997                 }
7998                 case CEE_STELEM_I:
7999                 case CEE_STELEM_I1:
8000                 case CEE_STELEM_I2:
8001                 case CEE_STELEM_I4:
8002                 case CEE_STELEM_I8:
8003                 case CEE_STELEM_R4:
8004                 case CEE_STELEM_R8:
8005                 case CEE_STELEM_REF:
8006                 case CEE_STELEM_ANY: {
8007                         MonoInst *addr;
8008
8009                         CHECK_STACK (3);
8010                         sp -= 3;
8011
8012                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8013
8014                         if (*ip == CEE_STELEM_ANY) {
8015                                 CHECK_OPSIZE (5);
8016                                 token = read32 (ip + 1);
8017                                 klass = mini_get_class (method, token, generic_context);
8018                                 CHECK_TYPELOAD (klass);
8019                                 mono_class_init (klass);
8020                         }
8021                         else
8022                                 klass = array_access_to_klass (*ip);
8023
8024                         if (sp [0]->type != STACK_OBJ)
8025                                 UNVERIFIED;
8026
8027                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8028                         if (generic_class_is_reference_type (cfg, klass) &&
8029                                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
8030                                 MonoMethod* helper = mono_marshal_get_stelemref ();
8031                                 MonoInst *iargs [3];
8032
8033                                 if (sp [0]->type != STACK_OBJ)
8034                                         UNVERIFIED;
8035                                 if (sp [2]->type != STACK_OBJ)
8036                                         UNVERIFIED;
8037
8038                                 iargs [2] = sp [2];
8039                                 iargs [1] = sp [1];
8040                                 iargs [0] = sp [0];
8041                                 
8042                                 mono_emit_method_call (cfg, helper, mono_method_signature (helper), iargs, NULL);
8043                         } else {
8044                                 if (sp [1]->opcode == OP_ICONST) {
8045                                         int array_reg = sp [0]->dreg;
8046                                         int index_reg = sp [1]->dreg;
8047                                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
8048
8049                                         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
8050                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
8051                                 } else {
8052                                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
8053                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
8054                                 }
8055                         }
8056
8057                         if (*ip == CEE_STELEM_ANY)
8058                                 ip += 5;
8059                         else
8060                                 ++ip;
8061                         inline_costs += 1;
8062                         break;
8063                 }
8064                 case CEE_CKFINITE: {
8065                         CHECK_STACK (1);
8066                         --sp;
8067
8068                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8069                         ins->sreg1 = sp [0]->dreg;
8070                         ins->dreg = alloc_freg (cfg);
8071                         ins->type = STACK_R8;
8072                         MONO_ADD_INS (bblock, ins);
8073                         *sp++ = ins;
8074
8075                         ++ip;
8076                         break;
8077                 }
8078                 case CEE_REFANYVAL: {
8079                         MonoInst *src_var, *src;
8080                         int context_used = 0;
8081
8082                         int klass_reg = alloc_preg (cfg);
8083                         int dreg = alloc_preg (cfg);
8084
8085                         CHECK_STACK (1);
8086                         MONO_INST_NEW (cfg, ins, *ip);
8087                         --sp;
8088                         CHECK_OPSIZE (5);
8089                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8090                         CHECK_TYPELOAD (klass);
8091                         mono_class_init (klass);
8092
8093                         if (cfg->generic_sharing_context) {
8094                                 context_used = mono_class_check_context_used (klass);
8095                                 if (context_used && cfg->compile_aot)
8096                                         GENERIC_SHARING_FAILURE (*ip);
8097                         }
8098
8099                         if (context_used) {
8100                                 // FIXME:
8101                                 GENERIC_SHARING_FAILURE (*ip);
8102                         } else {
8103                                 // FIXME:
8104                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
8105                                 if (!src_var)
8106                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
8107                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
8108                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
8109                                 mini_emit_class_check (cfg, klass_reg, klass);
8110                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
8111                         }
8112                         ins->type = STACK_MP;
8113                         *sp++ = ins;
8114                         ip += 5;
8115                         break;
8116                 }
8117                 case CEE_MKREFANY: {
8118                         MonoInst *loc, *addr;
8119                         int context_used = 0;
8120
8121                         CHECK_STACK (1);
8122                         MONO_INST_NEW (cfg, ins, *ip);
8123                         --sp;
8124                         CHECK_OPSIZE (5);
8125                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8126                         CHECK_TYPELOAD (klass);
8127                         mono_class_init (klass);
8128
8129                         if (cfg->generic_sharing_context) {
8130                                 context_used = mono_class_check_context_used (klass);
8131                                 if (context_used && cfg->compile_aot)
8132                                         GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8133                         }
8134
8135                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8136                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
8137
8138                         if (context_used) {
8139                                 GENERIC_SHARING_FAILURE (CEE_MKREFANY);
8140                         } else if (cfg->compile_aot) {
8141                                 int const_reg = alloc_preg (cfg);
8142                                 int type_reg = alloc_preg (cfg);
8143
8144                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
8145                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
8146                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
8147                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
8148                         } else {
8149                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
8150                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
8151                         }
8152                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
8153
8154                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
8155                         ins->type = STACK_VTYPE;
8156                         ins->klass = mono_defaults.typed_reference_class;
8157                         *sp++ = ins;
8158                         ip += 5;
8159                         break;
8160                 }
8161                 case CEE_LDTOKEN: {
8162                         gpointer handle;
8163                         MonoClass *handle_class;
8164                         int context_used = 0;
8165
8166                         CHECK_STACK_OVF (1);
8167
8168                         CHECK_OPSIZE (5);
8169                         n = read32 (ip + 1);
8170
8171                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
8172                                 handle = mono_method_get_wrapper_data (method, n);
8173                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8174                                 if (handle_class == mono_defaults.typehandle_class)
8175                                         handle = &((MonoClass*)handle)->byval_arg;
8176                         }
8177                         else {
8178                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8179                         }
8180                         if (!handle)
8181                                 goto load_error;
8182                         mono_class_init (handle_class);
8183                         if (cfg->generic_sharing_context) {
8184                                 if (handle_class == mono_defaults.typehandle_class) {
8185                                         /* If we get a MONO_TYPE_CLASS
8186                                            then we need to provide the
8187                                            open type, not an
8188                                            instantiation of it. */
8189                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8190                                                 context_used = 0;
8191                                         else
8192                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8193                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8194                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8195                                 else if (handle_class == mono_defaults.methodhandle_class)
8196                                         context_used = mono_method_check_context_used (handle);
8197                                 else
8198                                         g_assert_not_reached ();
8199                         }
8200
8201                         if (cfg->opt & MONO_OPT_SHARED) {
8202                                 MonoInst *addr, *vtvar, *iargs [3];
8203                                 int method_context_used;
8204
8205                                 if (cfg->generic_sharing_context)
8206                                         method_context_used = mono_method_check_context_used (method);
8207                                 else
8208                                         method_context_used = 0;
8209
8210                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8211
8212                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
8213                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
8214                                 if (method_context_used) {
8215                                         MonoInst *rgctx;
8216
8217                                         EMIT_GET_RGCTX (rgctx, method_context_used);
8218                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used, rgctx, method, MONO_RGCTX_INFO_METHOD);
8219                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
8220                                 } else {
8221                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
8222                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
8223                                 }
8224                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8225
8226                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8227
8228                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8229                         } else {
8230                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
8231                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8232                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8233                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8234                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8235                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8236
8237                                         mono_class_init (tclass);
8238                                         if (context_used) {
8239                                                 MonoInst *rgctx;
8240
8241                                                 g_assert (!cfg->compile_aot);
8242                                                 EMIT_GET_RGCTX (rgctx, context_used);
8243                                                 ins = emit_get_rgctx_klass (cfg, context_used, rgctx, tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
8244                                         } else if (cfg->compile_aot) {
8245                                                 /*
8246                                                  * FIXME: We would have to include the context into the
8247                                                  * aot constant too (tests/generic-array-type.2.exe).
8248                                                  */
8249                                                 if (generic_context)
8250                                                         cfg->disable_aot = TRUE;
8251                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n);
8252                                         } else {
8253                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8254                                         }
8255                                         ins->type = STACK_OBJ;
8256                                         ins->klass = cmethod->klass;
8257                                         ip += 5;
8258                                 } else {
8259                                         MonoInst *addr, *vtvar;
8260
8261                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8262
8263                                         if (context_used) {
8264                                                         MonoInst *rgctx;
8265
8266                                                 g_assert (!cfg->compile_aot);
8267
8268                                                 EMIT_GET_RGCTX (rgctx, context_used);
8269                                                 if (handle_class == mono_defaults.typehandle_class) {
8270                                                         ins = emit_get_rgctx_klass (cfg, context_used, rgctx,
8271                                                                         mono_class_from_mono_type (handle),
8272                                                                         MONO_RGCTX_INFO_TYPE);
8273                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8274                                                         ins = emit_get_rgctx_method (cfg, context_used, rgctx,
8275                                                                         handle, MONO_RGCTX_INFO_METHOD);
8276                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8277                                                         ins = emit_get_rgctx_field (cfg, context_used, rgctx,
8278                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
8279                                                 } else {
8280                                                         g_assert_not_reached ();
8281                                                 }
8282                                         } else if (cfg->compile_aot) {
8283                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n);
8284                                         } else {
8285                                                 EMIT_NEW_PCONST (cfg, ins, handle);
8286                                         }
8287                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8288                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8289                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8290                                 }
8291                         }
8292
8293                         *sp++ = ins;
8294                         ip += 5;
8295                         break;
8296                 }
8297                 case CEE_THROW:
8298                         CHECK_STACK (1);
8299                         MONO_INST_NEW (cfg, ins, OP_THROW);
8300                         --sp;
8301                         ins->sreg1 = sp [0]->dreg;
8302                         ip++;
8303                         bblock->out_of_line = TRUE;
8304                         MONO_ADD_INS (bblock, ins);
8305                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
8306                         MONO_ADD_INS (bblock, ins);
8307                         sp = stack_start;
8308                         
8309                         link_bblock (cfg, bblock, end_bblock);
8310                         start_new_bblock = 1;
8311                         break;
8312                 case CEE_ENDFINALLY:
8313                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8314                         MONO_ADD_INS (bblock, ins);
8315                         ip++;
8316                         start_new_bblock = 1;
8317
8318                         /*
8319                          * Control will leave the method so empty the stack, otherwise
8320                          * the next basic block will start with a nonempty stack.
8321                          */
8322                         while (sp != stack_start) {
8323                                 sp--;
8324                         }
8325                         break;
8326                 case CEE_LEAVE:
8327                 case CEE_LEAVE_S: {
8328                         GList *handlers;
8329
8330                         if (*ip == CEE_LEAVE) {
8331                                 CHECK_OPSIZE (5);
8332                                 target = ip + 5 + (gint32)read32(ip + 1);
8333                         } else {
8334                                 CHECK_OPSIZE (2);
8335                                 target = ip + 2 + (signed char)(ip [1]);
8336                         }
8337
8338                         /* empty the stack */
8339                         while (sp != stack_start) {
8340                                 sp--;
8341                         }
8342
8343                         /* 
8344                          * If this leave statement is in a catch block, check for a
8345                          * pending exception, and rethrow it if necessary.
8346                          */
8347                         for (i = 0; i < header->num_clauses; ++i) {
8348                                 MonoExceptionClause *clause = &header->clauses [i];
8349
8350                                 /* 
8351                                  * Use <= in the final comparison to handle clauses with multiple
8352                                  * leave statements, like in bug #78024.
8353                                  * The ordering of the exception clauses guarantees that we find the
8354                                  * innermost clause.
8355                                  */
8356                                 if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && (clause->flags == MONO_EXCEPTION_CLAUSE_NONE) && (ip - header->code + ((*ip == CEE_LEAVE) ? 5 : 2)) <= (clause->handler_offset + clause->handler_len)) {
8357                                         MonoInst *exc_ins;
8358                                         MonoBasicBlock *dont_throw;
8359
8360                                         /*
8361                                           MonoInst *load;
8362
8363                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8364                                         */
8365
8366                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
8367
8368                                         NEW_BBLOCK (cfg, dont_throw);
8369
8370                                         /*
8371                                          * Currently, we allways rethrow the abort exception, despite the 
8372                                          * fact that this is not correct. See thread6.cs for an example. 
8373                                          * But propagating the abort exception is more important than 
8374                                          * getting the sematics right.
8375                                          */
8376                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
8377                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
8378                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
8379
8380                                         MONO_START_BB (cfg, dont_throw);
8381                                         bblock = cfg->cbb;
8382                                 }
8383                         }
8384
8385                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
8386                                 GList *tmp;
8387                                 for (tmp = handlers; tmp; tmp = tmp->next) {
8388                                         tblock = tmp->data;
8389                                         link_bblock (cfg, bblock, tblock);
8390                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
8391                                         ins->inst_target_bb = tblock;
8392                                         MONO_ADD_INS (bblock, ins);
8393                                 }
8394                                 g_list_free (handlers);
8395                         } 
8396
8397                         MONO_INST_NEW (cfg, ins, OP_BR);
8398                         MONO_ADD_INS (bblock, ins);
8399                         GET_BBLOCK (cfg, tblock, target);
8400                         link_bblock (cfg, bblock, tblock);
8401                         CHECK_BBLOCK (target, ip, tblock);
8402                         ins->inst_target_bb = tblock;
8403                         start_new_bblock = 1;
8404
8405                         if (*ip == CEE_LEAVE)
8406                                 ip += 5;
8407                         else
8408                                 ip += 2;
8409
8410                         break;
8411                 }
8412
8413                         /*
8414                          * Mono specific opcodes
8415                          */
8416                 case MONO_CUSTOM_PREFIX: {
8417
8418                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
8419
8420                         CHECK_OPSIZE (2);
8421                         switch (ip [1]) {
8422                         case CEE_MONO_ICALL: {
8423                                 gpointer func;
8424                                 MonoJitICallInfo *info;
8425
8426                                 token = read32 (ip + 2);
8427                                 func = mono_method_get_wrapper_data (method, token);
8428                                 info = mono_find_jit_icall_by_addr (func);
8429                                 g_assert (info);
8430
8431                                 CHECK_STACK (info->sig->param_count);
8432                                 sp -= info->sig->param_count;
8433
8434                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
8435                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
8436                                         *sp++ = ins;
8437
8438                                 ip += 6;
8439                                 inline_costs += 10 * num_calls++;
8440
8441                                 break;
8442                         }
8443                         case CEE_MONO_LDPTR: {
8444                                 gpointer ptr;
8445
8446                                 CHECK_STACK_OVF (1);
8447                                 CHECK_OPSIZE (6);
8448                                 token = read32 (ip + 2);
8449
8450                                 ptr = mono_method_get_wrapper_data (method, token);
8451                                 if (cfg->compile_aot && (cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE || cfg->method->wrapper_type == MONO_WRAPPER_RUNTIME_INVOKE)) {
8452                                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (cfg->method);
8453
8454                                         if (wrapped && ptr != NULL && mono_lookup_internal_call (wrapped) == ptr) {
8455                                                 EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, wrapped);
8456                                                 *sp++ = ins;
8457                                                 ip += 6;
8458                                                 break;
8459                                         }
8460
8461                                         if ((method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
8462                                                 MonoJitICallInfo *callinfo;
8463                                                 const char *icall_name;
8464
8465                                                 icall_name = method->name + strlen ("__icall_wrapper_");
8466                                                 g_assert (icall_name);
8467                                                 callinfo = mono_find_jit_icall_by_name (icall_name);
8468                                                 g_assert (callinfo);
8469
8470                                                 if (ptr == callinfo->func) {
8471                                                         /* Will be transformed into an AOTCONST later */
8472                                                         EMIT_NEW_PCONST (cfg, ins, ptr);
8473                                                         *sp++ = ins;
8474                                                         ip += 6;
8475                                                         break;
8476                                                 }
8477                                         }
8478                                 }
8479                                 /* FIXME: Generalize this */
8480                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
8481                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
8482                                         *sp++ = ins;
8483                                         ip += 6;
8484                                         break;
8485                                 }
8486                                 EMIT_NEW_PCONST (cfg, ins, ptr);
8487                                 *sp++ = ins;
8488                                 ip += 6;
8489                                 inline_costs += 10 * num_calls++;
8490                                 /* Can't embed random pointers into AOT code */
8491                                 cfg->disable_aot = 1;
8492                                 break;
8493                         }
8494                         case CEE_MONO_VTADDR: {
8495                                 MonoInst *src_var, *src;
8496
8497                                 CHECK_STACK (1);
8498                                 --sp;
8499
8500                                 // FIXME:
8501                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
8502                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
8503                                 *sp++ = src;
8504                                 ip += 2;
8505                                 break;
8506                         }
8507                         case CEE_MONO_NEWOBJ: {
8508                                 MonoInst *iargs [2];
8509
8510                                 CHECK_STACK_OVF (1);
8511                                 CHECK_OPSIZE (6);
8512                                 token = read32 (ip + 2);
8513                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8514                                 mono_class_init (klass);
8515                                 NEW_DOMAINCONST (cfg, iargs [0]);
8516                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
8517                                 NEW_CLASSCONST (cfg, iargs [1], klass);
8518                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
8519                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
8520                                 ip += 6;
8521                                 inline_costs += 10 * num_calls++;
8522                                 break;
8523                         }
8524                         case CEE_MONO_OBJADDR:
8525                                 CHECK_STACK (1);
8526                                 --sp;
8527                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
8528                                 ins->dreg = alloc_preg (cfg);
8529                                 ins->sreg1 = sp [0]->dreg;
8530                                 ins->type = STACK_MP;
8531                                 MONO_ADD_INS (cfg->cbb, ins);
8532                                 *sp++ = ins;
8533                                 ip += 2;
8534                                 break;
8535                         case CEE_MONO_LDNATIVEOBJ:
8536                                 /*
8537                                  * Similar to LDOBJ, but instead load the unmanaged 
8538                                  * representation of the vtype to the stack.
8539                                  */
8540                                 CHECK_STACK (1);
8541                                 CHECK_OPSIZE (6);
8542                                 --sp;
8543                                 token = read32 (ip + 2);
8544                                 klass = mono_method_get_wrapper_data (method, token);
8545                                 g_assert (klass->valuetype);
8546                                 mono_class_init (klass);
8547
8548                                 {
8549                                         MonoInst *src, *dest, *temp;
8550
8551                                         src = sp [0];
8552                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
8553                                         temp->backend.is_pinvoke = 1;
8554                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
8555                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
8556
8557                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
8558                                         dest->type = STACK_VTYPE;
8559                                         dest->klass = klass;
8560
8561                                         *sp ++ = dest;
8562                                         ip += 6;
8563                                 }
8564                                 break;
8565                         case CEE_MONO_RETOBJ: {
8566                                 /*
8567                                  * Same as RET, but return the native representation of a vtype
8568                                  * to the caller.
8569                                  */
8570                                 g_assert (cfg->ret);
8571                                 g_assert (mono_method_signature (method)->pinvoke); 
8572                                 CHECK_STACK (1);
8573                                 --sp;
8574                                 
8575                                 CHECK_OPSIZE (6);
8576                                 token = read32 (ip + 2);    
8577                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8578
8579                                 EMIT_NEW_RETLOADA (cfg, ins);
8580                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
8581                                 
8582                                 if (sp != stack_start)
8583                                         UNVERIFIED;
8584                                 
8585                                 MONO_INST_NEW (cfg, ins, OP_BR);
8586                                 ins->inst_target_bb = end_bblock;
8587                                 MONO_ADD_INS (bblock, ins);
8588                                 link_bblock (cfg, bblock, end_bblock);
8589                                 start_new_bblock = 1;
8590                                 ip += 6;
8591                                 break;
8592                         }
8593                         case CEE_MONO_CISINST:
8594                         case CEE_MONO_CCASTCLASS: {
8595                                 int token;
8596                                 CHECK_STACK (1);
8597                                 --sp;
8598                                 CHECK_OPSIZE (6);
8599                                 token = read32 (ip + 2);
8600                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
8601                                 if (ip [1] == CEE_MONO_CISINST)
8602                                         ins = handle_cisinst (cfg, klass, sp [0]);
8603                                 else
8604                                         ins = handle_ccastclass (cfg, klass, sp [0]);
8605                                 bblock = cfg->cbb;
8606                                 *sp++ = ins;
8607                                 ip += 6;
8608                                 break;
8609                         }
8610                         case CEE_MONO_SAVE_LMF:
8611                         case CEE_MONO_RESTORE_LMF:
8612 #ifdef MONO_ARCH_HAVE_LMF_OPS
8613                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
8614                                 MONO_ADD_INS (bblock, ins);
8615                                 cfg->need_lmf_area = TRUE;
8616 #endif
8617                                 ip += 2;
8618                                 break;
8619                         case CEE_MONO_CLASSCONST:
8620                                 CHECK_STACK_OVF (1);
8621                                 CHECK_OPSIZE (6);
8622                                 token = read32 (ip + 2);
8623                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
8624                                 *sp++ = ins;
8625                                 ip += 6;
8626                                 inline_costs += 10 * num_calls++;
8627                                 break;
8628                         case CEE_MONO_NOT_TAKEN:
8629                                 bblock->out_of_line = TRUE;
8630                                 ip += 2;
8631                                 break;
8632                         case CEE_MONO_TLS:
8633                                 CHECK_STACK_OVF (1);
8634                                 CHECK_OPSIZE (6);
8635                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
8636                                 ins->dreg = alloc_preg (cfg);
8637                                 ins->inst_offset = (gint32)read32 (ip + 2);
8638                                 ins->type = STACK_PTR;
8639                                 MONO_ADD_INS (bblock, ins);
8640                                 *sp++ = ins;
8641                                 ip += 6;
8642                                 break;
8643                         default:
8644                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
8645                                 break;
8646                         }
8647                         break;
8648                 }
8649
8650                 case CEE_PREFIX1: {
8651                         CHECK_OPSIZE (2);
8652                         switch (ip [1]) {
8653                         case CEE_ARGLIST: {
8654                                 /* somewhat similar to LDTOKEN */
8655                                 MonoInst *addr, *vtvar;
8656                                 CHECK_STACK_OVF (1);
8657                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
8658
8659                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8660                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
8661
8662                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8663                                 ins->type = STACK_VTYPE;
8664                                 ins->klass = mono_defaults.argumenthandle_class;
8665                                 *sp++ = ins;
8666                                 ip += 2;
8667                                 break;
8668                         }
8669                         case CEE_CEQ:
8670                         case CEE_CGT:
8671                         case CEE_CGT_UN:
8672                         case CEE_CLT:
8673                         case CEE_CLT_UN: {
8674                                 MonoInst *cmp;
8675                                 CHECK_STACK (2);
8676                                 /*
8677                                  * The following transforms:
8678                                  *    CEE_CEQ    into OP_CEQ
8679                                  *    CEE_CGT    into OP_CGT
8680                                  *    CEE_CGT_UN into OP_CGT_UN
8681                                  *    CEE_CLT    into OP_CLT
8682                                  *    CEE_CLT_UN into OP_CLT_UN
8683                                  */
8684                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
8685                                 
8686                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
8687                                 sp -= 2;
8688                                 cmp->sreg1 = sp [0]->dreg;
8689                                 cmp->sreg2 = sp [1]->dreg;
8690                                 type_from_op (cmp, sp [0], sp [1]);
8691                                 CHECK_TYPE (cmp);
8692                                 if ((sp [0]->type == STACK_I8) || ((sizeof (gpointer) == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
8693                                         cmp->opcode = OP_LCOMPARE;
8694                                 else if (sp [0]->type == STACK_R8)
8695                                         cmp->opcode = OP_FCOMPARE;
8696                                 else
8697                                         cmp->opcode = OP_ICOMPARE;
8698                                 MONO_ADD_INS (bblock, cmp);
8699                                 ins->type = STACK_I4;
8700                                 ins->dreg = alloc_dreg (cfg, ins->type);
8701                                 type_from_op (ins, sp [0], sp [1]);
8702
8703                                 if (cmp->opcode == OP_FCOMPARE) {
8704                                         /*
8705                                          * The backends expect the fceq opcodes to do the
8706                                          * comparison too.
8707                                          */
8708                                         cmp->opcode = OP_NOP;
8709                                         ins->sreg1 = cmp->sreg1;
8710                                         ins->sreg2 = cmp->sreg2;
8711                                 }
8712                                 MONO_ADD_INS (bblock, ins);
8713                                 *sp++ = ins;
8714                                 ip += 2;
8715                                 break;
8716                         }
8717                         case CEE_LDFTN: {
8718                                 MonoInst *argconst;
8719                                 MonoMethod *cil_method, *ctor_method;
8720                                 gboolean is_shared;
8721
8722                                 CHECK_STACK_OVF (1);
8723                                 CHECK_OPSIZE (6);
8724                                 n = read32 (ip + 2);
8725                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
8726                                 if (!cmethod)
8727                                         goto load_error;
8728                                 mono_class_init (cmethod->klass);
8729  
8730                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8731                                         GENERIC_SHARING_FAILURE (CEE_LDFTN);
8732
8733                                 is_shared = (cmethod->flags & METHOD_ATTRIBUTE_STATIC) &&
8734                                         (cmethod->klass->generic_class || cmethod->klass->generic_container) &&
8735                                         mono_class_generic_sharing_enabled (cmethod->klass);
8736
8737                                 cil_method = cmethod;
8738                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
8739                                         METHOD_ACCESS_FAILURE;
8740
8741                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8742                                         if (check_linkdemand (cfg, method, cmethod))
8743                                                 INLINE_FAILURE;
8744                                         CHECK_CFG_EXCEPTION;
8745                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8746                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8747                                 }
8748
8749                                 /* 
8750                                  * Optimize the common case of ldftn+delegate creation
8751                                  */
8752 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
8753                                 /* FIXME: SGEN support */
8754                                 if (!is_shared && (sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context)) && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
8755                                         MonoInst *target_ins;
8756
8757                                         ip += 6;
8758                                         if (cfg->verbose_level > 3)
8759                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8760                                         target_ins = sp [-1];
8761                                         sp --;
8762                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod);
8763                                         ip += 5;                                        
8764                                         sp ++;
8765                                         break;
8766                                 }
8767 #endif
8768
8769                                 if (is_shared)
8770                                         EMIT_NEW_METHODCONST (cfg, argconst, mono_marshal_get_static_rgctx_invoke (cmethod));
8771                                 else
8772                                         EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
8773                                 if (method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED)
8774                                         ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
8775                                 else
8776                                         ins = mono_emit_jit_icall (cfg, mono_ldftn_nosync, &argconst);
8777                                 *sp++ = ins;
8778                                 
8779                                 ip += 6;
8780                                 inline_costs += 10 * num_calls++;
8781                                 break;
8782                         }
8783                         case CEE_LDVIRTFTN: {
8784                                 MonoInst *args [2];
8785
8786                                 CHECK_STACK (1);
8787                                 CHECK_OPSIZE (6);
8788                                 n = read32 (ip + 2);
8789                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
8790                                 if (!cmethod)
8791                                         goto load_error;
8792                                 mono_class_init (cmethod->klass);
8793  
8794                                 if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8795                                         GENERIC_SHARING_FAILURE (CEE_LDVIRTFTN);
8796
8797                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
8798                                         if (check_linkdemand (cfg, method, cmethod))
8799                                                 INLINE_FAILURE;
8800                                         CHECK_CFG_EXCEPTION;
8801                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
8802                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
8803                                 }
8804
8805                                 --sp;
8806                                 args [0] = *sp;
8807                                 EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
8808                                 *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
8809
8810                                 ip += 6;
8811                                 inline_costs += 10 * num_calls++;
8812                                 break;
8813                         }
8814                         case CEE_LDARG:
8815                                 CHECK_STACK_OVF (1);
8816                                 CHECK_OPSIZE (4);
8817                                 n = read16 (ip + 2);
8818                                 CHECK_ARG (n);
8819                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
8820                                 *sp++ = ins;
8821                                 ip += 4;
8822                                 break;
8823                         case CEE_LDARGA:
8824                                 CHECK_STACK_OVF (1);
8825                                 CHECK_OPSIZE (4);
8826                                 n = read16 (ip + 2);
8827                                 CHECK_ARG (n);
8828                                 NEW_ARGLOADA (cfg, ins, n);
8829                                 MONO_ADD_INS (cfg->cbb, ins);
8830                                 *sp++ = ins;
8831                                 ip += 4;
8832                                 break;
8833                         case CEE_STARG:
8834                                 CHECK_STACK (1);
8835                                 --sp;
8836                                 CHECK_OPSIZE (4);
8837                                 n = read16 (ip + 2);
8838                                 CHECK_ARG (n);
8839                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
8840                                         UNVERIFIED;
8841                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8842                                 ip += 4;
8843                                 break;
8844                         case CEE_LDLOC:
8845                                 CHECK_STACK_OVF (1);
8846                                 CHECK_OPSIZE (4);
8847                                 n = read16 (ip + 2);
8848                                 CHECK_LOCAL (n);
8849                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
8850                                 *sp++ = ins;
8851                                 ip += 4;
8852                                 break;
8853                         case CEE_LDLOCA:
8854                                 CHECK_STACK_OVF (1);
8855                                 CHECK_OPSIZE (4);
8856                                 n = read16 (ip + 2);
8857                                 CHECK_LOCAL (n);
8858                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
8859                                 *sp++ = ins;
8860                                 ip += 4;
8861                                 break;
8862                         case CEE_STLOC:
8863                                 CHECK_STACK (1);
8864                                 --sp;
8865                                 CHECK_OPSIZE (4);
8866                                 n = read16 (ip + 2);
8867                                 CHECK_LOCAL (n);
8868                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8869                                         UNVERIFIED;
8870                                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
8871                                 ip += 4;
8872                                 inline_costs += 1;
8873                                 break;
8874                         case CEE_LOCALLOC:
8875                                 CHECK_STACK (1);
8876                                 --sp;
8877                                 if (sp != stack_start) 
8878                                         UNVERIFIED;
8879                                 if (cfg->method != method) 
8880                                         /* 
8881                                          * Inlining this into a loop in a parent could lead to 
8882                                          * stack overflows which is different behavior than the
8883                                          * non-inlined case, thus disable inlining in this case.
8884                                          */
8885                                         goto inline_failure;
8886
8887                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8888                                 ins->dreg = alloc_preg (cfg);
8889                                 ins->sreg1 = sp [0]->dreg;
8890                                 ins->type = STACK_PTR;
8891                                 MONO_ADD_INS (cfg->cbb, ins);
8892
8893                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8894                                 if (header->init_locals)
8895                                         ins->flags |= MONO_INST_INIT;
8896
8897                                 *sp++ = ins;
8898                                 ip += 2;
8899                                 break;
8900                         case CEE_ENDFILTER: {
8901                                 MonoExceptionClause *clause, *nearest;
8902                                 int cc, nearest_num;
8903
8904                                 CHECK_STACK (1);
8905                                 --sp;
8906                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
8907                                         UNVERIFIED;
8908                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
8909                                 ins->sreg1 = (*sp)->dreg;
8910                                 MONO_ADD_INS (bblock, ins);
8911                                 start_new_bblock = 1;
8912                                 ip += 2;
8913
8914                                 nearest = NULL;
8915                                 nearest_num = 0;
8916                                 for (cc = 0; cc < header->num_clauses; ++cc) {
8917                                         clause = &header->clauses [cc];
8918                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
8919                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
8920                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
8921                                                 nearest = clause;
8922                                                 nearest_num = cc;
8923                                         }
8924                                 }
8925                                 g_assert (nearest);
8926                                 if ((ip - header->code) != nearest->handler_offset)
8927                                         UNVERIFIED;
8928
8929                                 break;
8930                         }
8931                         case CEE_UNALIGNED_:
8932                                 ins_flag |= MONO_INST_UNALIGNED;
8933                                 /* FIXME: record alignment? we can assume 1 for now */
8934                                 CHECK_OPSIZE (3);
8935                                 ip += 3;
8936                                 break;
8937                         case CEE_VOLATILE_:
8938                                 ins_flag |= MONO_INST_VOLATILE;
8939                                 ip += 2;
8940                                 break;
8941                         case CEE_TAIL_:
8942                                 ins_flag   |= MONO_INST_TAILCALL;
8943                                 cfg->flags |= MONO_CFG_HAS_TAIL;
8944                                 /* Can't inline tail calls at this time */
8945                                 inline_costs += 100000;
8946                                 ip += 2;
8947                                 break;
8948                         case CEE_INITOBJ:
8949                                 CHECK_STACK (1);
8950                                 --sp;
8951                                 CHECK_OPSIZE (6);
8952                                 token = read32 (ip + 2);
8953                                 klass = mini_get_class (method, token, generic_context);
8954                                 CHECK_TYPELOAD (klass);
8955                                 if (generic_class_is_reference_type (cfg, klass)) {
8956                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
8957                                 } else {
8958                                         GENERIC_SHARING_FAILURE (CEE_INITOBJ);
8959                                         mini_emit_initobj (cfg, *sp, NULL, klass);
8960                                 }
8961                                 ip += 6;
8962                                 inline_costs += 1;
8963                                 break;
8964                         case CEE_CONSTRAINED_:
8965                                 CHECK_OPSIZE (6);
8966                                 token = read32 (ip + 2);
8967                                 constrained_call = mono_class_get_full (image, token, generic_context);
8968                                 CHECK_TYPELOAD (constrained_call);
8969                                 ip += 6;
8970                                 break;
8971                         case CEE_CPBLK:
8972                         case CEE_INITBLK: {
8973                                 MonoInst *iargs [3];
8974                                 CHECK_STACK (3);
8975                                 sp -= 3;
8976
8977                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
8978                                         mini_emit_memcpy2 (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
8979                                 } else if ((ip [1] == CEE_INITBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
8980                                         /* emit_memset only works when val == 0 */
8981                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
8982                                 } else {
8983                                         iargs [0] = sp [0];
8984                                         iargs [1] = sp [1];
8985                                         iargs [2] = sp [2];
8986                                         if (ip [1] == CEE_CPBLK) {
8987                                                 MonoMethod *memcpy_method = get_memcpy_method ();
8988                                                 mono_emit_method_call (cfg, memcpy_method, memcpy_method->signature, iargs, NULL);
8989                                         } else {
8990                                                 MonoMethod *memset_method = get_memset_method ();
8991                                                 mono_emit_method_call (cfg, memset_method, memset_method->signature, iargs, NULL);
8992                                         }
8993                                 }
8994                                 ip += 2;
8995                                 inline_costs += 1;
8996                                 break;
8997                         }
8998                         case CEE_NO_:
8999                                 CHECK_OPSIZE (3);
9000                                 if (ip [2] & 0x1)
9001                                         ins_flag |= MONO_INST_NOTYPECHECK;
9002                                 if (ip [2] & 0x2)
9003                                         ins_flag |= MONO_INST_NORANGECHECK;
9004                                 /* we ignore the no-nullcheck for now since we
9005                                  * really do it explicitly only when doing callvirt->call
9006                                  */
9007                                 ip += 3;
9008                                 break;
9009                         case CEE_RETHROW: {
9010                                 MonoInst *load;
9011                                 int handler_offset = -1;
9012
9013                                 for (i = 0; i < header->num_clauses; ++i) {
9014                                         MonoExceptionClause *clause = &header->clauses [i];
9015                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY))
9016                                                 handler_offset = clause->handler_offset;
9017                                 }
9018
9019                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9020
9021                                 g_assert (handler_offset != -1);
9022
9023                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9024                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9025                                 ins->sreg1 = load->dreg;
9026                                 MONO_ADD_INS (bblock, ins);
9027                                 sp = stack_start;
9028                                 link_bblock (cfg, bblock, end_bblock);
9029                                 start_new_bblock = 1;
9030                                 ip += 2;
9031                                 break;
9032                         }
9033                         case CEE_SIZEOF: {
9034                                 guint32 align;
9035                                 int ialign;
9036
9037                                 GENERIC_SHARING_FAILURE (CEE_SIZEOF);
9038
9039                                 CHECK_STACK_OVF (1);
9040                                 CHECK_OPSIZE (6);
9041                                 token = read32 (ip + 2);
9042                                 /* FIXXME: handle generics. */
9043                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9044                                         MonoType *type = mono_type_create_from_typespec (image, token);
9045                                         token = mono_type_size (type, &ialign);
9046                                 } else {
9047                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9048                                         CHECK_TYPELOAD (klass);
9049                                         mono_class_init (klass);
9050                                         token = mono_class_value_size (klass, &align);
9051                                 }
9052                                 EMIT_NEW_ICONST (cfg, ins, token);
9053                                 *sp++= ins;
9054                                 ip += 6;
9055                                 break;
9056                         }
9057                         case CEE_REFANYTYPE: {
9058                                 MonoInst *src_var, *src;
9059
9060                                 CHECK_STACK (1);
9061                                 --sp;
9062
9063                                 // FIXME:
9064                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9065                                 if (!src_var)
9066                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
9067                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
9068                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typed_reference_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
9069                                 *sp++ = ins;
9070                                 ip += 2;
9071                                 break;
9072                         }
9073                         case CEE_READONLY_:
9074                                 readonly = TRUE;
9075                                 ip += 2;
9076                                 break;
9077                         default:
9078                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9079                         }
9080                         break;
9081                 }
9082                 default:
9083                         g_error ("opcode 0x%02x not handled", *ip);
9084                 }
9085         }
9086         if (start_new_bblock != 1)
9087                 UNVERIFIED;
9088
9089         bblock->cil_length = ip - bblock->cil_code;
9090         bblock->next_bb = end_bblock;
9091
9092         if (cfg->method == method && cfg->domainvar) {
9093                 MonoInst *store;
9094                 MonoInst *get_domain;
9095
9096                 cfg->cbb = init_localsbb;
9097
9098                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9099                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
9100                 }
9101                 else {
9102                         get_domain->dreg = alloc_preg (cfg);
9103                         MONO_ADD_INS (cfg->cbb, get_domain);
9104                 }               
9105                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9106                 MONO_ADD_INS (cfg->cbb, store);
9107         }
9108
9109         if (cfg->method == method && cfg->got_var)
9110                 mono_emit_load_got_addr (cfg);
9111
9112         if (header->init_locals) {
9113                 MonoInst *store;
9114
9115                 cfg->cbb = init_localsbb;
9116                 cfg->ip = header->code;
9117                 for (i = 0; i < header->num_locals; ++i) {
9118                         MonoType *ptype = header->locals [i];
9119                         int t = ptype->type;
9120                         dreg = cfg->locals [i]->dreg;
9121
9122                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9123                                 t = ptype->data.klass->enum_basetype->type;
9124                         if (ptype->byref) {
9125                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9126                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9127                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
9128                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9129                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
9130                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9131                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9132                                 ins->type = STACK_R8;
9133                                 ins->inst_p0 = (void*)&r8_0;
9134                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
9135                                 MONO_ADD_INS (init_localsbb, ins);
9136                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
9137                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9138 +                                  ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9139                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
9140                         } else {
9141                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9142                         }
9143                 }
9144         }
9145
9146         cfg->ip = NULL;
9147
9148         /* resolve backward branches in the middle of an existing basic block */
9149         for (tmp = bb_recheck; tmp; tmp = tmp->next) {
9150                 bblock = tmp->data;
9151                 /*printf ("need recheck in %s at IL_%04x\n", method->name, bblock->cil_code - header->code);*/
9152                 tblock = find_previous (cfg->cil_offset_to_bb, header->code_size, start_bblock, bblock->cil_code);
9153                 if (tblock != start_bblock) {
9154                         int l;
9155                         split_bblock (cfg, tblock, bblock);
9156                         l = bblock->cil_code - header->code;
9157                         bblock->cil_length = tblock->cil_length - l;
9158                         tblock->cil_length = l;
9159                 } else {
9160                         printf ("recheck failed.\n");
9161                 }
9162         }
9163
9164         if (cfg->method == method) {
9165                 MonoBasicBlock *bb;
9166                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9167                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9168                         if (cfg->spvars)
9169                                 mono_create_spvar_for_region (cfg, bb->region);
9170                         if (cfg->verbose_level > 2)
9171                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9172                 }
9173         }
9174
9175         g_slist_free (class_inits);
9176         dont_inline = g_list_remove (dont_inline, method);
9177
9178         if (inline_costs < 0) {
9179                 char *mname;
9180
9181                 /* Method is too large */
9182                 mname = mono_method_full_name (method, TRUE);
9183                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9184                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9185                 g_free (mname);
9186                 return -1;
9187         }
9188
9189         if ((cfg->verbose_level > 1) && (cfg->method == method)) 
9190                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
9191
9192         return inline_costs;
9193  
9194  exception_exit:
9195         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9196         g_slist_free (class_inits);
9197         dont_inline = g_list_remove (dont_inline, method);
9198         return -1;
9199
9200  inline_failure:
9201         g_slist_free (class_inits);
9202         dont_inline = g_list_remove (dont_inline, method);
9203         return -1;
9204
9205  load_error:
9206         g_slist_free (class_inits);
9207         dont_inline = g_list_remove (dont_inline, method);
9208         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9209         return -1;
9210
9211  unverified:
9212         g_slist_free (class_inits);
9213         dont_inline = g_list_remove (dont_inline, method);
9214         set_exception_type_from_invalid_il (cfg, method, ip);
9215         return -1;
9216 }
9217
9218 static int
9219 store_membase_reg_to_store_membase_imm (int opcode)
9220 {
9221         switch (opcode) {
9222         case OP_STORE_MEMBASE_REG:
9223                 return OP_STORE_MEMBASE_IMM;
9224         case OP_STOREI1_MEMBASE_REG:
9225                 return OP_STOREI1_MEMBASE_IMM;
9226         case OP_STOREI2_MEMBASE_REG:
9227                 return OP_STOREI2_MEMBASE_IMM;
9228         case OP_STOREI4_MEMBASE_REG:
9229                 return OP_STOREI4_MEMBASE_IMM;
9230         case OP_STOREI8_MEMBASE_REG:
9231                 return OP_STOREI8_MEMBASE_IMM;
9232         default:
9233                 g_assert_not_reached ();
9234         }
9235
9236         return -1;
9237 }               
9238
9239 int
9240 mono_op_to_op_imm (int opcode)
9241 {
9242         switch (opcode) {
9243         case OP_IADD:
9244                 return OP_IADD_IMM;
9245         case OP_ISUB:
9246                 return OP_ISUB_IMM;
9247         case OP_IDIV:
9248                 return OP_IDIV_IMM;
9249         case OP_IDIV_UN:
9250                 return OP_IDIV_UN_IMM;
9251         case OP_IREM:
9252                 return OP_IREM_IMM;
9253         case OP_IREM_UN:
9254                 return OP_IREM_UN_IMM;
9255         case OP_IMUL:
9256                 return OP_IMUL_IMM;
9257         case OP_IAND:
9258                 return OP_IAND_IMM;
9259         case OP_IOR:
9260                 return OP_IOR_IMM;
9261         case OP_IXOR:
9262                 return OP_IXOR_IMM;
9263         case OP_ISHL:
9264                 return OP_ISHL_IMM;
9265         case OP_ISHR:
9266                 return OP_ISHR_IMM;
9267         case OP_ISHR_UN:
9268                 return OP_ISHR_UN_IMM;
9269
9270         case OP_LADD:
9271                 return OP_LADD_IMM;
9272         case OP_LSUB:
9273                 return OP_LSUB_IMM;
9274         case OP_LAND:
9275                 return OP_LAND_IMM;
9276         case OP_LOR:
9277                 return OP_LOR_IMM;
9278         case OP_LXOR:
9279                 return OP_LXOR_IMM;
9280         case OP_LSHL:
9281                 return OP_LSHL_IMM;
9282         case OP_LSHR:
9283                 return OP_LSHR_IMM;
9284         case OP_LSHR_UN:
9285                 return OP_LSHR_UN_IMM;          
9286
9287         case OP_COMPARE:
9288                 return OP_COMPARE_IMM;
9289         case OP_ICOMPARE:
9290                 return OP_ICOMPARE_IMM;
9291         case OP_LCOMPARE:
9292                 return OP_LCOMPARE_IMM;
9293
9294         case OP_STORE_MEMBASE_REG:
9295                 return OP_STORE_MEMBASE_IMM;
9296         case OP_STOREI1_MEMBASE_REG:
9297                 return OP_STOREI1_MEMBASE_IMM;
9298         case OP_STOREI2_MEMBASE_REG:
9299                 return OP_STOREI2_MEMBASE_IMM;
9300         case OP_STOREI4_MEMBASE_REG:
9301                 return OP_STOREI4_MEMBASE_IMM;
9302
9303 #if defined(__i386__) || defined (__x86_64__)
9304         case OP_X86_PUSH:
9305                 return OP_X86_PUSH_IMM;
9306         case OP_X86_COMPARE_MEMBASE_REG:
9307                 return OP_X86_COMPARE_MEMBASE_IMM;
9308 #endif
9309 #if defined(__x86_64__)
9310         case OP_AMD64_ICOMPARE_MEMBASE_REG:
9311                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
9312 #endif
9313         case OP_VOIDCALL_REG:
9314                 return OP_VOIDCALL;
9315         case OP_CALL_REG:
9316                 return OP_CALL;
9317         case OP_LCALL_REG:
9318                 return OP_LCALL;
9319         case OP_FCALL_REG:
9320                 return OP_FCALL;
9321         case OP_LOCALLOC:
9322                 return OP_LOCALLOC_IMM;
9323         }
9324
9325         return -1;
9326 }
9327
9328 static int
9329 ldind_to_load_membase (int opcode)
9330 {
9331         switch (opcode) {
9332         case CEE_LDIND_I1:
9333                 return OP_LOADI1_MEMBASE;
9334         case CEE_LDIND_U1:
9335                 return OP_LOADU1_MEMBASE;
9336         case CEE_LDIND_I2:
9337                 return OP_LOADI2_MEMBASE;
9338         case CEE_LDIND_U2:
9339                 return OP_LOADU2_MEMBASE;
9340         case CEE_LDIND_I4:
9341                 return OP_LOADI4_MEMBASE;
9342         case CEE_LDIND_U4:
9343                 return OP_LOADU4_MEMBASE;
9344         case CEE_LDIND_I:
9345                 return OP_LOAD_MEMBASE;
9346         case CEE_LDIND_REF:
9347                 return OP_LOAD_MEMBASE;
9348         case CEE_LDIND_I8:
9349                 return OP_LOADI8_MEMBASE;
9350         case CEE_LDIND_R4:
9351                 return OP_LOADR4_MEMBASE;
9352         case CEE_LDIND_R8:
9353                 return OP_LOADR8_MEMBASE;
9354         default:
9355                 g_assert_not_reached ();
9356         }
9357
9358         return -1;
9359 }
9360
9361 static int
9362 stind_to_store_membase (int opcode)
9363 {
9364         switch (opcode) {
9365         case CEE_STIND_I1:
9366                 return OP_STOREI1_MEMBASE_REG;
9367         case CEE_STIND_I2:
9368                 return OP_STOREI2_MEMBASE_REG;
9369         case CEE_STIND_I4:
9370                 return OP_STOREI4_MEMBASE_REG;
9371         case CEE_STIND_I:
9372         case CEE_STIND_REF:
9373                 return OP_STORE_MEMBASE_REG;
9374         case CEE_STIND_I8:
9375                 return OP_STOREI8_MEMBASE_REG;
9376         case CEE_STIND_R4:
9377                 return OP_STORER4_MEMBASE_REG;
9378         case CEE_STIND_R8:
9379                 return OP_STORER8_MEMBASE_REG;
9380         default:
9381                 g_assert_not_reached ();
9382         }
9383
9384         return -1;
9385 }
9386
9387 int
9388 mono_load_membase_to_load_mem (int opcode)
9389 {
9390         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
9391 #if defined(__i386__) || defined(__x86_64__)
9392         switch (opcode) {
9393         case OP_LOAD_MEMBASE:
9394                 return OP_LOAD_MEM;
9395         case OP_LOADU1_MEMBASE:
9396                 return OP_LOADU1_MEM;
9397         case OP_LOADU2_MEMBASE:
9398                 return OP_LOADU2_MEM;
9399         case OP_LOADI4_MEMBASE:
9400                 return OP_LOADI4_MEM;
9401         case OP_LOADU4_MEMBASE:
9402                 return OP_LOADU4_MEM;
9403 #if SIZEOF_VOID_P == 8
9404         case OP_LOADI8_MEMBASE:
9405                 return OP_LOADI8_MEM;
9406 #endif
9407         }
9408 #endif
9409
9410         return -1;
9411 }
9412
9413 static inline int
9414 op_to_op_dest_membase (int store_opcode, int opcode)
9415 {
9416 #if defined(__i386__)
9417         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
9418                 return -1;
9419
9420         switch (opcode) {
9421         case OP_IADD:
9422                 return OP_X86_ADD_MEMBASE_REG;
9423         case OP_ISUB:
9424                 return OP_X86_SUB_MEMBASE_REG;
9425         case OP_IAND:
9426                 return OP_X86_AND_MEMBASE_REG;
9427         case OP_IOR:
9428                 return OP_X86_OR_MEMBASE_REG;
9429         case OP_IXOR:
9430                 return OP_X86_XOR_MEMBASE_REG;
9431         case OP_ADD_IMM:
9432         case OP_IADD_IMM:
9433                 return OP_X86_ADD_MEMBASE_IMM;
9434         case OP_SUB_IMM:
9435         case OP_ISUB_IMM:
9436                 return OP_X86_SUB_MEMBASE_IMM;
9437         case OP_AND_IMM:
9438         case OP_IAND_IMM:
9439                 return OP_X86_AND_MEMBASE_IMM;
9440         case OP_OR_IMM:
9441         case OP_IOR_IMM:
9442                 return OP_X86_OR_MEMBASE_IMM;
9443         case OP_XOR_IMM:
9444         case OP_IXOR_IMM:
9445                 return OP_X86_XOR_MEMBASE_IMM;
9446         case OP_MOVE:
9447                 return OP_NOP;
9448         }
9449 #endif
9450
9451 #if defined(__x86_64__)
9452         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
9453                 return -1;
9454
9455         switch (opcode) {
9456         case OP_IADD:
9457                 return OP_X86_ADD_MEMBASE_REG;
9458         case OP_ISUB:
9459                 return OP_X86_SUB_MEMBASE_REG;
9460         case OP_IAND:
9461                 return OP_X86_AND_MEMBASE_REG;
9462         case OP_IOR:
9463                 return OP_X86_OR_MEMBASE_REG;
9464         case OP_IXOR:
9465                 return OP_X86_XOR_MEMBASE_REG;
9466         case OP_IADD_IMM:
9467                 return OP_X86_ADD_MEMBASE_IMM;
9468         case OP_ISUB_IMM:
9469                 return OP_X86_SUB_MEMBASE_IMM;
9470         case OP_IAND_IMM:
9471                 return OP_X86_AND_MEMBASE_IMM;
9472         case OP_IOR_IMM:
9473                 return OP_X86_OR_MEMBASE_IMM;
9474         case OP_IXOR_IMM:
9475                 return OP_X86_XOR_MEMBASE_IMM;
9476         case OP_LADD:
9477                 return OP_AMD64_ADD_MEMBASE_REG;
9478         case OP_LSUB:
9479                 return OP_AMD64_SUB_MEMBASE_REG;
9480         case OP_LAND:
9481                 return OP_AMD64_AND_MEMBASE_REG;
9482         case OP_LOR:
9483                 return OP_AMD64_OR_MEMBASE_REG;
9484         case OP_LXOR:
9485                 return OP_AMD64_XOR_MEMBASE_REG;
9486         case OP_ADD_IMM:
9487         case OP_LADD_IMM:
9488                 return OP_AMD64_ADD_MEMBASE_IMM;
9489         case OP_SUB_IMM:
9490         case OP_LSUB_IMM:
9491                 return OP_AMD64_SUB_MEMBASE_IMM;
9492         case OP_AND_IMM:
9493         case OP_LAND_IMM:
9494                 return OP_AMD64_AND_MEMBASE_IMM;
9495         case OP_OR_IMM:
9496         case OP_LOR_IMM:
9497                 return OP_AMD64_OR_MEMBASE_IMM;
9498         case OP_XOR_IMM:
9499         case OP_LXOR_IMM:
9500                 return OP_AMD64_XOR_MEMBASE_IMM;
9501         case OP_MOVE:
9502                 return OP_NOP;
9503         }
9504 #endif
9505
9506         return -1;
9507 }
9508
9509 static inline int
9510 op_to_op_store_membase (int store_opcode, int opcode)
9511 {
9512 #if defined(__i386__) || defined(__x86_64__)
9513         switch (opcode) {
9514         case OP_ICEQ:
9515                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
9516                         return OP_X86_SETEQ_MEMBASE;
9517         case OP_CNE:
9518                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
9519                         return OP_X86_SETNE_MEMBASE;
9520         }
9521 #endif
9522
9523         return -1;
9524 }
9525
9526 static inline int
9527 op_to_op_src1_membase (int load_opcode, int opcode)
9528 {
9529 #ifdef __i386__
9530         /* FIXME: This has sign extension issues */
9531         /*
9532         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
9533                 return OP_X86_COMPARE_MEMBASE8_IMM;
9534         */
9535
9536         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
9537                 return -1;
9538
9539         switch (opcode) {
9540         case OP_X86_PUSH:
9541                 return OP_X86_PUSH_MEMBASE;
9542         case OP_COMPARE_IMM:
9543         case OP_ICOMPARE_IMM:
9544                 return OP_X86_COMPARE_MEMBASE_IMM;
9545         case OP_COMPARE:
9546         case OP_ICOMPARE:
9547                 return OP_X86_COMPARE_MEMBASE_REG;
9548         }
9549 #endif
9550
9551 #ifdef __x86_64__
9552         /* FIXME: This has sign extension issues */
9553         /*
9554         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
9555                 return OP_X86_COMPARE_MEMBASE8_IMM;
9556         */
9557
9558         switch (opcode) {
9559         case OP_X86_PUSH:
9560                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
9561                         return OP_X86_PUSH_MEMBASE;
9562                 break;
9563                 /* FIXME: This only works for 32 bit immediates
9564         case OP_COMPARE_IMM:
9565         case OP_LCOMPARE_IMM:
9566                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
9567                         return OP_AMD64_COMPARE_MEMBASE_IMM;
9568                 */
9569         case OP_ICOMPARE_IMM:
9570                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9571                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
9572                 break;
9573         case OP_COMPARE:
9574         case OP_LCOMPARE:
9575                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
9576                         return OP_AMD64_COMPARE_MEMBASE_REG;
9577                 break;
9578         case OP_ICOMPARE:
9579                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9580                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
9581                 break;
9582         }
9583 #endif
9584
9585         return -1;
9586 }
9587
9588 static inline int
9589 op_to_op_src2_membase (int load_opcode, int opcode)
9590 {
9591 #ifdef __i386__
9592         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
9593                 return -1;
9594         
9595         switch (opcode) {
9596         case OP_COMPARE:
9597         case OP_ICOMPARE:
9598                 return OP_X86_COMPARE_REG_MEMBASE;
9599         case OP_IADD:
9600                 return OP_X86_ADD_REG_MEMBASE;
9601         case OP_ISUB:
9602                 return OP_X86_SUB_REG_MEMBASE;
9603         case OP_IAND:
9604                 return OP_X86_AND_REG_MEMBASE;
9605         case OP_IOR:
9606                 return OP_X86_OR_REG_MEMBASE;
9607         case OP_IXOR:
9608                 return OP_X86_XOR_REG_MEMBASE;
9609         }
9610 #endif
9611
9612 #ifdef __x86_64__
9613         switch (opcode) {
9614         case OP_ICOMPARE:
9615                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9616                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
9617                 break;
9618         case OP_COMPARE:
9619         case OP_LCOMPARE:
9620                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9621                         return OP_AMD64_COMPARE_REG_MEMBASE;
9622                 break;
9623         case OP_IADD:
9624                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9625                         return OP_X86_ADD_REG_MEMBASE;
9626         case OP_ISUB:
9627                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9628                         return OP_X86_SUB_REG_MEMBASE;
9629         case OP_IAND:
9630                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9631                         return OP_X86_AND_REG_MEMBASE;
9632         case OP_IOR:
9633                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9634                         return OP_X86_OR_REG_MEMBASE;
9635         case OP_IXOR:
9636                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
9637                         return OP_X86_XOR_REG_MEMBASE;
9638         case OP_LADD:
9639                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9640                         return OP_AMD64_ADD_REG_MEMBASE;
9641         case OP_LSUB:
9642                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9643                         return OP_AMD64_SUB_REG_MEMBASE;
9644         case OP_LAND:
9645                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9646                         return OP_AMD64_AND_REG_MEMBASE;
9647         case OP_LOR:
9648                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9649                         return OP_AMD64_OR_REG_MEMBASE;
9650         case OP_LXOR:
9651                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
9652                         return OP_AMD64_XOR_REG_MEMBASE;
9653         }
9654 #endif
9655
9656         return -1;
9657 }
9658
9659 int
9660 mono_op_to_op_imm_noemul (int opcode)
9661 {
9662         switch (opcode) {
9663 #if SIZEOF_VOID_P == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPTS)
9664         case OP_LSHR:
9665         case OP_LSHL:
9666         case OP_LSHR_UN:
9667 #endif
9668 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9669         case OP_IDIV:
9670         case OP_IDIV_UN:
9671         case OP_IREM:
9672         case OP_IREM_UN:
9673 #endif
9674                 return -1;
9675         default:
9676                 return mono_op_to_op_imm (opcode);
9677         }
9678 }
9679
9680 /**
9681  * mono_handle_global_vregs:
9682  *
9683  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
9684  * for them.
9685  */
9686 void
9687 mono_handle_global_vregs (MonoCompile *cfg)
9688 {
9689         gint32 *vreg_to_bb;
9690         MonoBasicBlock *bb;
9691         int i, pos;
9692
9693         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
9694
9695         /* Find local vregs used in more than one bb */
9696         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9697                 MonoInst *ins = bb->code;       
9698                 int block_num = bb->block_num;
9699
9700                 if (cfg->verbose_level > 1)
9701                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
9702
9703                 cfg->cbb = bb;
9704                 for (; ins; ins = ins->next) {
9705                         const char *spec = INS_INFO (ins->opcode);
9706                         int regtype, regindex;
9707                         gint32 prev_bb;
9708
9709                         if (G_UNLIKELY (cfg->verbose_level > 1))
9710                                 mono_print_ins (ins);
9711
9712                         g_assert (ins->opcode >= MONO_CEE_LAST);
9713
9714                         for (regindex = 0; regindex < 3; regindex ++) {
9715                                 int vreg;
9716
9717                                 if (regindex == 0) {
9718                                         regtype = spec [MONO_INST_DEST];
9719                                         if (regtype == ' ')
9720                                                 continue;
9721                                         vreg = ins->dreg;
9722                                 } else if (regindex == 1) {
9723                                         regtype = spec [MONO_INST_SRC1];
9724                                         if (regtype == ' ')
9725                                                 continue;
9726                                         vreg = ins->sreg1;
9727                                 } else {
9728                                         regtype = spec [MONO_INST_SRC2];
9729                                         if (regtype == ' ')
9730                                                 continue;
9731                                         vreg = ins->sreg2;
9732                                 }
9733
9734 #if SIZEOF_VOID_P == 4
9735                                 if (regtype == 'l') {
9736                                         /*
9737                                          * Since some instructions reference the original long vreg,
9738                                          * and some reference the two component vregs, it is quite hard
9739                                          * to determine when it needs to be global. So be conservative.
9740                                          */
9741                                         if (!get_vreg_to_inst (cfg, vreg)) {
9742                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
9743
9744                                                 if (cfg->verbose_level > 1)
9745                                                         printf ("LONG VREG R%d made global.\n", vreg);
9746
9747                                                 /*
9748                                                  * Make the component vregs volatile since the optimizations can
9749                                                  * get confused otherwise.
9750                                                  */
9751                                                 get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
9752                                                 get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
9753                                         }
9754                                 }
9755 #endif
9756
9757                                 g_assert (vreg != -1);
9758
9759                                 prev_bb = vreg_to_bb [vreg];
9760                                 if (prev_bb == 0) {
9761                                         /* 0 is a valid block num */
9762                                         vreg_to_bb [vreg] = block_num + 1;
9763                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
9764                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
9765                                                 continue;
9766
9767                                         if (!get_vreg_to_inst (cfg, vreg)) {
9768                                                 if (G_UNLIKELY (cfg->verbose_level > 1))
9769                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
9770
9771                                                 switch (regtype) {
9772                                                 case 'i':
9773                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
9774                                                         break;
9775                                                 case 'f':
9776                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
9777                                                         break;
9778                                                 case 'v':
9779                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
9780                                                         break;
9781                                                 default:
9782                                                         g_assert_not_reached ();
9783                                                 }
9784                                         }
9785
9786                                         /* Flag as having been used in more than one bb */
9787                                         vreg_to_bb [vreg] = -1;
9788                                 }
9789                         }
9790                 }
9791         }
9792
9793         /* If a variable is used in only one bblock, convert it into a local vreg */
9794         for (i = 0; i < cfg->num_varinfo; i++) {
9795                 MonoInst *var = cfg->varinfo [i];
9796                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
9797
9798                 switch (var->type) {
9799                 case STACK_I4:
9800                 case STACK_OBJ:
9801                 case STACK_PTR:
9802                 case STACK_MP:
9803                 case STACK_VTYPE:
9804 #if SIZEOF_VOID_P == 8
9805                 case STACK_I8:
9806 #endif
9807 #if !defined(__i386__) && !defined(MONO_ARCH_SOFT_FLOAT)
9808                 /* Enabling this screws up the fp stack on x86 */
9809                 case STACK_R8:
9810 #endif
9811                         /* Arguments are implicitly global */
9812                         /* Putting R4 vars into registers doesn't work currently */
9813                         if ((var->opcode != OP_ARG) && (var != cfg->ret) && !(var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && (vreg_to_bb [var->dreg] != -1) && (var->klass->byval_arg.type != MONO_TYPE_R4)) {
9814                                 /* 
9815                                  * Make that the variable's liveness interval doesn't contain a call, since
9816                                  * that would cause the lvreg to be spilled, making the whole optimization
9817                                  * useless.
9818                                  */
9819                                 /* This is too slow for JIT compilation */
9820 #if 0
9821                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
9822                                         MonoInst *ins;
9823                                         int def_index, call_index, ins_index;
9824                                         gboolean spilled = FALSE;
9825
9826                                         def_index = -1;
9827                                         call_index = -1;
9828                                         ins_index = 0;
9829                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
9830                                                 const char *spec = INS_INFO (ins->opcode);
9831
9832                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
9833                                                         def_index = ins_index;
9834
9835                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
9836                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
9837                                                         if (call_index > def_index) {
9838                                                                 spilled = TRUE;
9839                                                                 break;
9840                                                         }
9841                                                 }
9842
9843                                                 if (MONO_IS_CALL (ins))
9844                                                         call_index = ins_index;
9845
9846                                                 ins_index ++;
9847                                         }
9848
9849                                         if (spilled)
9850                                                 break;
9851                                 }
9852 #endif
9853
9854                                 if (G_UNLIKELY (cfg->verbose_level > 2))
9855                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
9856                                 var->flags |= MONO_INST_IS_DEAD;
9857                                 cfg->vreg_to_inst [var->dreg] = NULL;
9858                         }
9859                         break;
9860                 }
9861         }
9862
9863         /* 
9864          * Compress the varinfo and vars tables so the liveness computation is faster and
9865          * takes up less space.
9866          */
9867         pos = 0;
9868         for (i = 0; i < cfg->num_varinfo; ++i) {
9869                 MonoInst *var = cfg->varinfo [i];
9870                 if (pos < i && cfg->locals_start == i)
9871                         cfg->locals_start = pos;
9872                 if (!(var->flags & MONO_INST_IS_DEAD)) {
9873                         if (pos < i) {
9874                                 cfg->varinfo [pos] = cfg->varinfo [i];
9875                                 cfg->varinfo [pos]->inst_c0 = pos;
9876                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
9877                                 cfg->vars [pos].idx = pos;
9878 #if SIZEOF_VOID_P == 4
9879                                 if (cfg->varinfo [pos]->type == STACK_I8) {
9880                                         /* Modify the two component vars too */
9881                                         MonoInst *var1;
9882
9883                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
9884                                         var1->inst_c0 = pos;
9885                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
9886                                         var1->inst_c0 = pos;
9887                                 }
9888 #endif
9889                         }
9890                         pos ++;
9891                 }
9892         }
9893         cfg->num_varinfo = pos;
9894         if (cfg->locals_start > cfg->num_varinfo)
9895                 cfg->locals_start = cfg->num_varinfo;
9896 }
9897
9898 /**
9899  * mono_spill_global_vars:
9900  *
9901  *   Generate spill code for variables which are not allocated to registers, 
9902  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
9903  * code is generated which could be optimized by the local optimization passes.
9904  */
9905 void
9906 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
9907 {
9908         MonoBasicBlock *bb;
9909         char spec2 [16];
9910         int orig_next_vreg;
9911         guint32 *vreg_to_lvreg;
9912         guint32 *lvregs;
9913         guint32 i, lvregs_len;
9914         gboolean dest_has_lvreg = FALSE;
9915         guint32 stacktypes [128];
9916
9917         *need_local_opts = FALSE;
9918
9919         memset (spec2, 0, sizeof (spec2));
9920
9921         /* FIXME: Move this function to mini.c */
9922         stacktypes ['i'] = STACK_PTR;
9923         stacktypes ['l'] = STACK_I8;
9924         stacktypes ['f'] = STACK_R8;
9925
9926 #if SIZEOF_VOID_P == 4
9927         /* Create MonoInsts for longs */
9928         for (i = 0; i < cfg->num_varinfo; i++) {
9929                 MonoInst *ins = cfg->varinfo [i];
9930
9931                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
9932                         switch (ins->type) {
9933 #ifdef MONO_ARCH_SOFT_FLOAT
9934                         case STACK_R8:
9935 #endif
9936                         case STACK_I8: {
9937                                 MonoInst *tree;
9938
9939                                 g_assert (ins->opcode == OP_REGOFFSET);
9940
9941                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
9942                                 g_assert (tree);
9943                                 tree->opcode = OP_REGOFFSET;
9944                                 tree->inst_basereg = ins->inst_basereg;
9945                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
9946
9947                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
9948                                 g_assert (tree);
9949                                 tree->opcode = OP_REGOFFSET;
9950                                 tree->inst_basereg = ins->inst_basereg;
9951                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
9952                                 break;
9953                         }
9954                         default:
9955                                 break;
9956                         }
9957                 }
9958         }
9959 #endif
9960
9961         /* FIXME: widening and truncation */
9962
9963         /*
9964          * As an optimization, when a variable allocated to the stack is first loaded into 
9965          * an lvreg, we will remember the lvreg and use it the next time instead of loading
9966          * the variable again.
9967          */
9968         orig_next_vreg = cfg->next_vreg;
9969         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
9970         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
9971         lvregs_len = 0;
9972         
9973         /* Add spill loads/stores */
9974         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9975                 MonoInst *ins;
9976
9977                 if (cfg->verbose_level > 1)
9978                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
9979
9980                 /* Clear vreg_to_lvreg array */
9981                 for (i = 0; i < lvregs_len; i++)
9982                         vreg_to_lvreg [lvregs [i]] = 0;
9983                 lvregs_len = 0;
9984
9985                 cfg->cbb = bb;
9986                 MONO_BB_FOR_EACH_INS (bb, ins) {
9987                         const char *spec = INS_INFO (ins->opcode);
9988                         int regtype, srcindex, sreg, tmp_reg, prev_dreg;
9989                         gboolean store, no_lvreg;
9990
9991                         if (G_UNLIKELY (cfg->verbose_level > 1))
9992                                 mono_print_ins (ins);
9993
9994                         if (ins->opcode == OP_NOP)
9995                                 continue;
9996
9997                         /* 
9998                          * We handle LDADDR here as well, since it can only be decomposed
9999                          * when variable addresses are known.
10000                          */
10001                         if (ins->opcode == OP_LDADDR) {
10002                                 MonoInst *var = ins->inst_p0;
10003
10004                                 if (var->opcode == OP_VTARG_ADDR) {
10005                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
10006                                         MonoInst *vtaddr = var->inst_left;
10007                                         if (vtaddr->opcode == OP_REGVAR) {
10008                                                 ins->opcode = OP_MOVE;
10009                                                 ins->sreg1 = vtaddr->dreg;
10010                                         }
10011                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
10012                                                 ins->opcode = OP_LOAD_MEMBASE;
10013                                                 ins->inst_basereg = vtaddr->inst_basereg;
10014                                                 ins->inst_offset = vtaddr->inst_offset;
10015                                         } else
10016                                                 NOT_IMPLEMENTED;
10017                                 } else {
10018                                         g_assert (var->opcode == OP_REGOFFSET);
10019
10020                                         ins->opcode = OP_ADD_IMM;
10021                                         ins->sreg1 = var->inst_basereg;
10022                                         ins->inst_imm = var->inst_offset;
10023                                 }
10024
10025                                 *need_local_opts = TRUE;
10026                                 spec = INS_INFO (ins->opcode);
10027                         }
10028
10029                         if (ins->opcode < MONO_CEE_LAST) {
10030                                 mono_print_ins (ins);
10031                                 g_assert_not_reached ();
10032                         }
10033
10034                         /*
10035                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
10036                          * src register.
10037                          * FIXME:
10038                          */
10039                         if (MONO_IS_STORE_MEMBASE (ins)) {
10040                                 tmp_reg = ins->dreg;
10041                                 ins->dreg = ins->sreg2;
10042                                 ins->sreg2 = tmp_reg;
10043                                 store = TRUE;
10044
10045                                 spec2 [MONO_INST_DEST] = ' ';
10046                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10047                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10048                                 spec = spec2;
10049                         } else if (MONO_IS_STORE_MEMINDEX (ins))
10050                                 g_assert_not_reached ();
10051                         else
10052                                 store = FALSE;
10053                         no_lvreg = FALSE;
10054
10055                         if (G_UNLIKELY (cfg->verbose_level > 1))
10056                                 printf ("\t %.3s %d %d %d\n", spec, ins->dreg, ins->sreg1, ins->sreg2);
10057
10058                         /***************/
10059                         /*    DREG     */
10060                         /***************/
10061                         regtype = spec [MONO_INST_DEST];
10062                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
10063                         prev_dreg = -1;
10064
10065                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
10066                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
10067                                 MonoInst *store_ins;
10068                                 int store_opcode;
10069
10070                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
10071
10072                                 if (var->opcode == OP_REGVAR) {
10073                                         ins->dreg = var->dreg;
10074                                 } else if ((ins->dreg == ins->sreg1) && (spec [MONO_INST_DEST] == 'i') && (spec [MONO_INST_SRC1] == 'i') && !vreg_to_lvreg [ins->dreg] && (op_to_op_dest_membase (store_opcode, ins->opcode) != -1)) {
10075                                         /* 
10076                                          * Instead of emitting a load+store, use a _membase opcode.
10077                                          */
10078                                         g_assert (var->opcode == OP_REGOFFSET);
10079                                         if (ins->opcode == OP_MOVE) {
10080                                                 NULLIFY_INS (ins);
10081                                         } else {
10082                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
10083                                                 ins->inst_basereg = var->inst_basereg;
10084                                                 ins->inst_offset = var->inst_offset;
10085                                                 ins->dreg = -1;
10086                                         }
10087                                         spec = INS_INFO (ins->opcode);
10088                                 } else {
10089                                         guint32 lvreg;
10090
10091                                         g_assert (var->opcode == OP_REGOFFSET);
10092
10093                                         prev_dreg = ins->dreg;
10094
10095                                         /* Invalidate any previous lvreg for this vreg */
10096                                         vreg_to_lvreg [ins->dreg] = 0;
10097
10098                                         lvreg = 0;
10099
10100 #ifdef MONO_ARCH_SOFT_FLOAT
10101                                         if (store_opcode == OP_STORER8_MEMBASE_REG) {
10102                                                 regtype = 'l';
10103                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
10104                                         }
10105 #endif
10106
10107                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
10108
10109                                         if (regtype == 'l') {
10110                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
10111                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10112                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
10113                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10114                                         }
10115                                         else {
10116                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
10117
10118                                                 /* Try to fuse the store into the instruction itself */
10119                                                 /* FIXME: Add more instructions */
10120                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
10121                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
10122                                                         ins->inst_imm = ins->inst_c0;
10123                                                         ins->inst_destbasereg = var->inst_basereg;
10124                                                         ins->inst_offset = var->inst_offset;
10125                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
10126                                                         ins->opcode = store_opcode;
10127                                                         ins->inst_destbasereg = var->inst_basereg;
10128                                                         ins->inst_offset = var->inst_offset;
10129
10130                                                         no_lvreg = TRUE;
10131
10132                                                         tmp_reg = ins->dreg;
10133                                                         ins->dreg = ins->sreg2;
10134                                                         ins->sreg2 = tmp_reg;
10135                                                         store = TRUE;
10136
10137                                                         spec2 [MONO_INST_DEST] = ' ';
10138                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10139                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10140                                                         spec = spec2;
10141                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
10142                                                         // FIXME: The backends expect the base reg to be in inst_basereg
10143                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
10144                                                         ins->dreg = -1;
10145                                                         ins->inst_basereg = var->inst_basereg;
10146                                                         ins->inst_offset = var->inst_offset;
10147                                                         spec = INS_INFO (ins->opcode);
10148                                                 } else {
10149                                                         /* printf ("INS: "); mono_print_ins (ins); */
10150                                                         /* Create a store instruction */
10151                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
10152
10153                                                         /* Insert it after the instruction */
10154                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
10155
10156                                                         /* 
10157                                                          * We can't assign ins->dreg to var->dreg here, since the
10158                                                          * sregs could use it. So set a flag, and do it after
10159                                                          * the sregs.
10160                                                          */
10161                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
10162                                                                 dest_has_lvreg = TRUE;
10163                                                 }
10164                                         }
10165                                 }
10166                         }
10167
10168                         /************/
10169                         /*  SREGS   */
10170                         /************/
10171                         for (srcindex = 0; srcindex < 2; ++srcindex) {
10172                                 regtype = spec [(srcindex == 0) ? MONO_INST_SRC1 : MONO_INST_SRC2];
10173                                 sreg = srcindex == 0 ? ins->sreg1 : ins->sreg2;
10174
10175                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
10176                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
10177                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
10178                                         MonoInst *load_ins;
10179                                         guint32 load_opcode;
10180
10181                                         if (var->opcode == OP_REGVAR) {
10182                                                 if (srcindex == 0)
10183                                                         ins->sreg1 = var->dreg;
10184                                                 else
10185                                                         ins->sreg2 = var->dreg;
10186                                                 continue;
10187                                         }
10188
10189                                         g_assert (var->opcode == OP_REGOFFSET);
10190                                                 
10191                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
10192
10193                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
10194
10195                                         if (vreg_to_lvreg [sreg]) {
10196                                                 /* The variable is already loaded to an lvreg */
10197                                                 if (G_UNLIKELY (cfg->verbose_level > 1))
10198                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
10199                                                 if (srcindex == 0)
10200                                                         ins->sreg1 = vreg_to_lvreg [sreg];
10201                                                 else
10202                                                         ins->sreg2 = vreg_to_lvreg [sreg];
10203                                                 continue;
10204                                         }
10205
10206                                         /* Try to fuse the load into the instruction */
10207                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
10208                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
10209                                                 ins->inst_basereg = var->inst_basereg;
10210                                                 ins->inst_offset = var->inst_offset;
10211                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
10212                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
10213                                                 ins->sreg2 = var->inst_basereg;
10214                                                 ins->inst_offset = var->inst_offset;
10215                                         } else {
10216                                                 if ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE)) {
10217                                                         ins->opcode = OP_NOP;
10218                                                         sreg = ins->dreg;
10219                                                 } else {
10220                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
10221
10222                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
10223
10224                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
10225                                                                 if (var->dreg == prev_dreg) {
10226                                                                         /*
10227                                                                          * sreg refers to the value loaded by the load
10228                                                                          * emitted below, but we need to use ins->dreg
10229                                                                          * since it refers to the store emitted earlier.
10230                                                                          */
10231                                                                         sreg = ins->dreg;
10232                                                                 }
10233                                                                 vreg_to_lvreg [var->dreg] = sreg;
10234                                                                 g_assert (lvregs_len < 1024);
10235                                                                 lvregs [lvregs_len ++] = var->dreg;
10236                                                         }
10237                                                 }
10238
10239                                                 if (srcindex == 0)
10240                                                         ins->sreg1 = sreg;
10241                                                 else
10242                                                         ins->sreg2 = sreg;
10243
10244                                                 if (regtype == 'l') {
10245                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
10246                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10247                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
10248                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10249                                                 }
10250                                                 else {
10251 #if SIZEOF_VOID_P == 4
10252                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
10253 #endif
10254                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
10255                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10256                                                 }
10257                                         }
10258                                 }
10259                         }
10260
10261                         if (dest_has_lvreg) {
10262                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
10263                                 g_assert (lvregs_len < 1024);
10264                                 lvregs [lvregs_len ++] = prev_dreg;
10265                                 dest_has_lvreg = FALSE;
10266                         }
10267
10268                         if (store) {
10269                                 tmp_reg = ins->dreg;
10270                                 ins->dreg = ins->sreg2;
10271                                 ins->sreg2 = tmp_reg;
10272                         }
10273
10274                         if (MONO_IS_CALL (ins)) {
10275                                 /* Clear vreg_to_lvreg array */
10276                                 for (i = 0; i < lvregs_len; i++)
10277                                         vreg_to_lvreg [lvregs [i]] = 0;
10278                                 lvregs_len = 0;
10279                         }
10280
10281                         if (cfg->verbose_level > 1)
10282                                 mono_print_ins_index (1, ins);
10283                 }
10284         }
10285 }
10286
10287 /**
10288  * FIXME:
10289  * - use 'iadd' instead of 'int_add'
10290  * - handling ovf opcodes: decompose in method_to_ir.
10291  * - unify iregs/fregs
10292  *   -> partly done, the missing parts are:
10293  *   - a more complete unification would involve unifying the hregs as well, so
10294  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
10295  *     would no longer map to the machine hregs, so the code generators would need to
10296  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
10297  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
10298  *     fp/non-fp branches speeds it up by about 15%.
10299  * - use sext/zext opcodes instead of shifts
10300  * - add OP_ICALL
10301  * - get rid of TEMPLOADs if possible and use vregs instead
10302  * - clean up usage of OP_P/OP_ opcodes
10303  * - cleanup usage of DUMMY_USE
10304  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
10305  *   stack
10306  * - set the stack type and allocate a dreg in the EMIT_NEW macros
10307  * - get rid of all the <foo>2 stuff when the new JIT is ready.
10308  * - make sure handle_stack_args () is called before the branch is emitted
10309  * - when the new IR is done, get rid of all unused stuff
10310  * - COMPARE/BEQ as separate instructions or unify them ?
10311  *   - keeping them separate allows specialized compare instructions like
10312  *     compare_imm, compare_membase
10313  *   - most back ends unify fp compare+branch, fp compare+ceq
10314  * - integrate handle_stack_args into inline_method
10315  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
10316  * - Things to backport to the old JIT:
10317  *   - op_atomic_exchange fix for amd64
10318  *   - localloc fix for amd64
10319  *   - x86 type_token change
10320  *   - lconv fixes
10321  *   - long eq/ne optimizations
10322  * - handle long shift opts on 32 bit platforms somehow: they require 
10323  *   3 sregs (2 for arg1 and 1 for arg2)
10324  * - make byref a 'normal' type.
10325  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
10326  *   variable if needed.
10327  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
10328  *   like inline_method.
10329  * - remove inlining restrictions
10330  * - remove mono_save_args.
10331  * - add 'introduce a new optimization to simplify some range checks'
10332  * - fix LNEG and enable cfold of INEG
10333  * - generalize x86 optimizations like ldelema as a peephole optimization
10334  * - add store_mem_imm for amd64
10335  * - optimize the loading of the interruption flag in the managed->native wrappers
10336  * - avoid special handling of OP_NOP in passes
10337  * - move code inserting instructions into one function/macro.
10338  * - cleanup the code replacement in decompose_long_opts ()
10339  * - try a coalescing phase after liveness analysis
10340  * - add float -> vreg conversion + local optimizations on !x86
10341  * - figure out how to handle decomposed branches during optimizations, ie.
10342  *   compare+branch, op_jump_table+op_br etc.
10343  * - promote RuntimeXHandles to vregs
10344  * - vtype cleanups:
10345  *   - add a NEW_VARLOADA_VREG macro
10346  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
10347  *   accessing vtype fields.
10348  * - get rid of I8CONST on 64 bit platforms
10349  * - dealing with the increase in code size due to branches created during opcode
10350  *   decomposition:
10351  *   - use extended basic blocks
10352  *     - all parts of the JIT
10353  *     - handle_global_vregs () && local regalloc
10354  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
10355  * - sources of increase in code size:
10356  *   - vtypes
10357  *   - long compares
10358  *   - isinst and castclass
10359  *   - lvregs not allocated to global registers even if used multiple times
10360  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
10361  *   meaningful.
10362  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
10363  * - add all micro optimizations from the old JIT
10364  * - put tree optimizations into the deadce pass
10365  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
10366  *   specific function.
10367  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
10368  *   fcompare + branchCC.
10369  * - sig->ret->byref seems to be set for some calls made from ldfld wrappers when
10370  *   running generics.exe.
10371  * - create a helper function for allocating a stack slot, taking into account 
10372  *   MONO_CFG_HAS_SPILLUP.
10373  * - merge new GC changes in mini.c.
10374  * - merge r68207.
10375  * - merge the ia64 switch changes.
10376  * - merge the mips conditional changes.
10377  * - remove unused opcodes from mini-ops.h, remove "op_" from the opcode names,
10378  *   remove the op_ opcodes from the cpu-..md files, clean up the cpu-..md files.
10379  * - make the cpu_ tables smaller when the usage of the cee_ opcodes is removed.
10380  * - optimize mono_regstate2_alloc_int/float.
10381  * - fix the pessimistic handling of variables accessed in exception handler blocks.
10382  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
10383  *   parts of the tree could be separated by other instructions, killing the tree
10384  *   arguments, or stores killing loads etc. Also, should we fold loads into other
10385  *   instructions if the result of the load is used multiple times ?
10386  * - make the REM_IMM optimization in mini-x86.c arch-independent.
10387  * - LAST MERGE: 108395.
10388  * - when returning vtypes in registers, generate IR and append it to the end of the
10389  *   last bb instead of doing it in the epilog.
10390  * - when the new JIT is done, use the ins emission macros in ir-emit.h instead of the 
10391  *   ones in inssel.h.
10392  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
10393  */
10394
10395 /*
10396
10397 NOTES
10398 -----
10399
10400 - When to decompose opcodes:
10401   - earlier: this makes some optimizations hard to implement, since the low level IR
10402   no longer contains the neccessary information. But it is easier to do.
10403   - later: harder to implement, enables more optimizations.
10404 - Branches inside bblocks:
10405   - created when decomposing complex opcodes. 
10406     - branches to another bblock: harmless, but not tracked by the branch 
10407       optimizations, so need to branch to a label at the start of the bblock.
10408     - branches to inside the same bblock: very problematic, trips up the local
10409       reg allocator. Can be fixed by spitting the current bblock, but that is a
10410       complex operation, since some local vregs can become global vregs etc.
10411 - Local/global vregs:
10412   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
10413     local register allocator.
10414   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
10415     structure, created by mono_create_var (). Assigned to hregs or the stack by
10416     the global register allocator.
10417 - When to do optimizations like alu->alu_imm:
10418   - earlier -> saves work later on since the IR will be smaller/simpler
10419   - later -> can work on more instructions
10420 - Handling of valuetypes:
10421   - When a vtype is pushed on the stack, a new tempotary is created, an 
10422     instruction computing its address (LDADDR) is emitted and pushed on
10423     the stack. Need to optimize cases when the vtype is used immediately as in
10424     argument passing, stloc etc.
10425 - Instead of the to_end stuff in the old JIT, simply call the function handling
10426   the values on the stack before emitting the last instruction of the bb.
10427 */