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