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