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