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