Revert "Revert "Merge branch 'master' of https://github.com/mono/mono""
[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  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/attrdefs.h>
39 #include <mono/metadata/loader.h>
40 #include <mono/metadata/tabledefs.h>
41 #include <mono/metadata/class.h>
42 #include <mono/metadata/object.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/opcodes.h>
45 #include <mono/metadata/mono-endian.h>
46 #include <mono/metadata/tokentype.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/debug-helpers.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/gc-internal.h>
52 #include <mono/metadata/security-manager.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/security-core-clr.h>
55 #include <mono/metadata/monitor.h>
56 #include <mono/metadata/profiler-private.h>
57 #include <mono/metadata/profiler.h>
58 #include <mono/metadata/debug-mono-symfile.h>
59 #include <mono/utils/mono-compiler.h>
60 #include <mono/utils/mono-memory-model.h>
61 #include <mono/metadata/mono-basic-block.h>
62
63 #include "mini.h"
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71
72 #define BRANCH_COST 10
73 #define INLINE_LENGTH_LIMIT 20
74 #define INLINE_FAILURE(msg) do {                                                                        \
75         if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE)) { \
76                 if (cfg->verbose_level >= 2)                                                                    \
77                         printf ("inline failed: %s\n", msg);                                            \
78                 goto inline_failure;                                                                                    \
79         } \
80         } while (0)
81 #define CHECK_CFG_EXCEPTION do {\
82                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
83                         goto exception_exit;\
84         } while (0)
85 #define METHOD_ACCESS_FAILURE do {      \
86                 char *method_fname = mono_method_full_name (method, TRUE);      \
87                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
88                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);             \
89                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
90                 g_free (method_fname);  \
91                 g_free (cil_method_fname);      \
92                 goto exception_exit;    \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE do {       \
95                 char *method_fname = mono_method_full_name (method, TRUE);      \
96                 char *field_fname = mono_field_full_name (field);       \
97                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);              \
98                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
99                 g_free (method_fname);  \
100                 g_free (field_fname);   \
101                 goto exception_exit;    \
102         } while (0)
103 #define GENERIC_SHARING_FAILURE(opcode) do {            \
104                 if (cfg->generic_sharing_context) {     \
105             if (cfg->verbose_level > 2) \
106                             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__); \
107                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
108                         goto exception_exit;    \
109                 }                       \
110         } while (0)
111 #define GSHAREDVT_FAILURE(opcode) do {          \
112         if (cfg->gsharedvt) {                                                                                           \
113                 cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __FILE__, __LINE__); \
114                 if (cfg->verbose_level >= 2)                                                                    \
115                         printf ("%s\n", cfg->exception_message); \
116                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
117                 goto exception_exit;                                                                                    \
118         }                                                                                                                                       \
119         } while (0)
120 #define OUT_OF_MEMORY_FAILURE do {      \
121                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
122                 goto exception_exit;    \
123         } while (0)
124 #define DISABLE_AOT(cfg) do { \
125                 if ((cfg)->verbose_level >= 2)                                            \
126                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
127                 (cfg)->disable_aot = TRUE;                                                        \
128         } while (0)
129
130 /* Determine whenever 'ins' represents a load of the 'this' argument */
131 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
132
133 static int ldind_to_load_membase (int opcode);
134 static int stind_to_store_membase (int opcode);
135
136 int mono_op_to_op_imm (int opcode);
137 int mono_op_to_op_imm_noemul (int opcode);
138
139 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
140
141 /* helper methods signatures */
142 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
143 static MonoMethodSignature *helper_sig_domain_get = NULL;
144 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
145 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
146 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
147 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
148 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
149
150 /*
151  * Instruction metadata
152  */
153 #ifdef MINI_OP
154 #undef MINI_OP
155 #endif
156 #ifdef MINI_OP3
157 #undef MINI_OP3
158 #endif
159 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
160 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
161 #define NONE ' '
162 #define IREG 'i'
163 #define FREG 'f'
164 #define VREG 'v'
165 #define XREG 'x'
166 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
167 #define LREG IREG
168 #else
169 #define LREG 'l'
170 #endif
171 /* keep in sync with the enum in mini.h */
172 const char
173 ins_info[] = {
174 #include "mini-ops.h"
175 };
176 #undef MINI_OP
177 #undef MINI_OP3
178
179 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
180 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
181 /* 
182  * This should contain the index of the last sreg + 1. This is not the same
183  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
184  */
185 const gint8 ins_sreg_counts[] = {
186 #include "mini-ops.h"
187 };
188 #undef MINI_OP
189 #undef MINI_OP3
190
191 #define MONO_INIT_VARINFO(vi,id) do { \
192         (vi)->range.first_use.pos.bid = 0xffff; \
193         (vi)->reg = -1; \
194         (vi)->idx = (id); \
195 } while (0)
196
197 void
198 mono_inst_set_src_registers (MonoInst *ins, int *regs)
199 {
200         ins->sreg1 = regs [0];
201         ins->sreg2 = regs [1];
202         ins->sreg3 = regs [2];
203 }
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_replace_type (type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return OP_MOVE;
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368 }
369
370 /*
371  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
372  * foo<T> (int i) { ldarg.0; box T; }
373  */
374 #define UNVERIFIED do { \
375         if (cfg->gsharedvt) { \
376                 if (cfg->verbose_level > 2)                                                                     \
377                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
378                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
379                 goto exception_exit;                                                                                    \
380         }                                                                                                                                       \
381         if (mini_get_debug_options ()->break_on_unverified) \
382                 G_BREAKPOINT (); \
383         else \
384                 goto unverified; \
385 } while (0)
386
387 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
388
389 #define TYPE_LOAD_ERROR(klass) do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else { cfg->exception_ptr = klass; goto load_error; } } while (0)
390
391 #define GET_BBLOCK(cfg,tblock,ip) do {  \
392                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
393                 if (!(tblock)) {        \
394                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
395             NEW_BBLOCK (cfg, (tblock)); \
396                         (tblock)->cil_code = (ip);      \
397                         ADD_BBLOCK (cfg, (tblock));     \
398                 } \
399         } while (0)
400
401 #if defined(TARGET_X86) || defined(TARGET_AMD64)
402 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
403                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
404                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
405                 (dest)->sreg1 = (sr1); \
406                 (dest)->sreg2 = (sr2); \
407                 (dest)->inst_imm = (imm); \
408                 (dest)->backend.shift_amount = (shift); \
409                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
410         } while (0)
411 #endif
412
413 #if SIZEOF_REGISTER == 8
414 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
415                 /* FIXME: Need to add many more cases */ \
416                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
417                         MonoInst *widen; \
418                         int dr = alloc_preg (cfg); \
419                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
420                         (ins)->sreg2 = widen->dreg; \
421                 } \
422         } while (0)
423 #else
424 #define ADD_WIDEN_OP(ins, arg1, arg2)
425 #endif
426
427 #define ADD_BINOP(op) do {      \
428                 MONO_INST_NEW (cfg, ins, (op)); \
429                 sp -= 2;        \
430                 ins->sreg1 = sp [0]->dreg;      \
431                 ins->sreg2 = sp [1]->dreg;      \
432                 type_from_op (ins, sp [0], sp [1]);     \
433                 CHECK_TYPE (ins);       \
434                 /* Have to insert a widening op */               \
435         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
436         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
437         MONO_ADD_INS ((cfg)->cbb, (ins)); \
438         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
439         } while (0)
440
441 #define ADD_UNOP(op) do {       \
442                 MONO_INST_NEW (cfg, ins, (op)); \
443                 sp--;   \
444                 ins->sreg1 = sp [0]->dreg;      \
445                 type_from_op (ins, sp [0], NULL);       \
446                 CHECK_TYPE (ins);       \
447         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
448         MONO_ADD_INS ((cfg)->cbb, (ins)); \
449                 *sp++ = mono_decompose_opcode (cfg, ins); \
450         } while (0)
451
452 #define ADD_BINCOND(next_block) do {    \
453                 MonoInst *cmp;  \
454                 sp -= 2; \
455                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
456                 cmp->sreg1 = sp [0]->dreg;      \
457                 cmp->sreg2 = sp [1]->dreg;      \
458                 type_from_op (cmp, sp [0], sp [1]);     \
459                 CHECK_TYPE (cmp);       \
460                 type_from_op (ins, sp [0], sp [1]);     \
461                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
462                 GET_BBLOCK (cfg, tblock, target);               \
463                 link_bblock (cfg, bblock, tblock);      \
464                 ins->inst_true_bb = tblock;     \
465                 if ((next_block)) {     \
466                         link_bblock (cfg, bblock, (next_block));        \
467                         ins->inst_false_bb = (next_block);      \
468                         start_new_bblock = 1;   \
469                 } else {        \
470                         GET_BBLOCK (cfg, tblock, ip);           \
471                         link_bblock (cfg, bblock, tblock);      \
472                         ins->inst_false_bb = tblock;    \
473                         start_new_bblock = 2;   \
474                 }       \
475                 if (sp != stack_start) {                                                                        \
476                     handle_stack_args (cfg, stack_start, sp - stack_start); \
477                         CHECK_UNVERIFIABLE (cfg); \
478                 } \
479         MONO_ADD_INS (bblock, cmp); \
480                 MONO_ADD_INS (bblock, ins);     \
481         } while (0)
482
483 /* *
484  * link_bblock: Links two basic blocks
485  *
486  * links two basic blocks in the control flow graph, the 'from'
487  * argument is the starting block and the 'to' argument is the block
488  * the control flow ends to after 'from'.
489  */
490 static void
491 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
492 {
493         MonoBasicBlock **newa;
494         int i, found;
495
496 #if 0
497         if (from->cil_code) {
498                 if (to->cil_code)
499                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
500                 else
501                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
502         } else {
503                 if (to->cil_code)
504                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
505                 else
506                         printf ("edge from entry to exit\n");
507         }
508 #endif
509
510         found = FALSE;
511         for (i = 0; i < from->out_count; ++i) {
512                 if (to == from->out_bb [i]) {
513                         found = TRUE;
514                         break;
515                 }
516         }
517         if (!found) {
518                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
519                 for (i = 0; i < from->out_count; ++i) {
520                         newa [i] = from->out_bb [i];
521                 }
522                 newa [i] = to;
523                 from->out_count++;
524                 from->out_bb = newa;
525         }
526
527         found = FALSE;
528         for (i = 0; i < to->in_count; ++i) {
529                 if (from == to->in_bb [i]) {
530                         found = TRUE;
531                         break;
532                 }
533         }
534         if (!found) {
535                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
536                 for (i = 0; i < to->in_count; ++i) {
537                         newa [i] = to->in_bb [i];
538                 }
539                 newa [i] = from;
540                 to->in_count++;
541                 to->in_bb = newa;
542         }
543 }
544
545 void
546 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
547 {
548         link_bblock (cfg, from, to);
549 }
550
551 /**
552  * mono_find_block_region:
553  *
554  *   We mark each basic block with a region ID. We use that to avoid BB
555  *   optimizations when blocks are in different regions.
556  *
557  * Returns:
558  *   A region token that encodes where this region is, and information
559  *   about the clause owner for this block.
560  *
561  *   The region encodes the try/catch/filter clause that owns this block
562  *   as well as the type.  -1 is a special value that represents a block
563  *   that is in none of try/catch/filter.
564  */
565 static int
566 mono_find_block_region (MonoCompile *cfg, int offset)
567 {
568         MonoMethodHeader *header = cfg->header;
569         MonoExceptionClause *clause;
570         int i;
571
572         for (i = 0; i < header->num_clauses; ++i) {
573                 clause = &header->clauses [i];
574                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
575                     (offset < (clause->handler_offset)))
576                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
577                            
578                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
579                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
580                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
581                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
582                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
583                         else
584                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
585                 }
586
587                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
588                         return ((i + 1) << 8) | clause->flags;
589         }
590
591         return -1;
592 }
593
594 static GList*
595 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
596 {
597         MonoMethodHeader *header = cfg->header;
598         MonoExceptionClause *clause;
599         int i;
600         GList *res = NULL;
601
602         for (i = 0; i < header->num_clauses; ++i) {
603                 clause = &header->clauses [i];
604                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
605                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
606                         if (clause->flags == type)
607                                 res = g_list_append (res, clause);
608                 }
609         }
610         return res;
611 }
612
613 static void
614 mono_create_spvar_for_region (MonoCompile *cfg, int region)
615 {
616         MonoInst *var;
617
618         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
619         if (var)
620                 return;
621
622         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
623         /* prevent it from being register allocated */
624         var->flags |= MONO_INST_VOLATILE;
625
626         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
627 }
628
629 MonoInst *
630 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
631 {
632         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
633 }
634
635 static MonoInst*
636 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
637 {
638         MonoInst *var;
639
640         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
641         if (var)
642                 return var;
643
644         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
645         /* prevent it from being register allocated */
646         var->flags |= MONO_INST_VOLATILE;
647
648         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
649
650         return var;
651 }
652
653 /*
654  * Returns the type used in the eval stack when @type is loaded.
655  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
656  */
657 void
658 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
659 {
660         MonoClass *klass;
661
662         type = mini_replace_type (type);
663         inst->klass = klass = mono_class_from_mono_type (type);
664         if (type->byref) {
665                 inst->type = STACK_MP;
666                 return;
667         }
668
669 handle_enum:
670         switch (type->type) {
671         case MONO_TYPE_VOID:
672                 inst->type = STACK_INV;
673                 return;
674         case MONO_TYPE_I1:
675         case MONO_TYPE_U1:
676         case MONO_TYPE_BOOLEAN:
677         case MONO_TYPE_I2:
678         case MONO_TYPE_U2:
679         case MONO_TYPE_CHAR:
680         case MONO_TYPE_I4:
681         case MONO_TYPE_U4:
682                 inst->type = STACK_I4;
683                 return;
684         case MONO_TYPE_I:
685         case MONO_TYPE_U:
686         case MONO_TYPE_PTR:
687         case MONO_TYPE_FNPTR:
688                 inst->type = STACK_PTR;
689                 return;
690         case MONO_TYPE_CLASS:
691         case MONO_TYPE_STRING:
692         case MONO_TYPE_OBJECT:
693         case MONO_TYPE_SZARRAY:
694         case MONO_TYPE_ARRAY:    
695                 inst->type = STACK_OBJ;
696                 return;
697         case MONO_TYPE_I8:
698         case MONO_TYPE_U8:
699                 inst->type = STACK_I8;
700                 return;
701         case MONO_TYPE_R4:
702         case MONO_TYPE_R8:
703                 inst->type = STACK_R8;
704                 return;
705         case MONO_TYPE_VALUETYPE:
706                 if (type->data.klass->enumtype) {
707                         type = mono_class_enum_basetype (type->data.klass);
708                         goto handle_enum;
709                 } else {
710                         inst->klass = klass;
711                         inst->type = STACK_VTYPE;
712                         return;
713                 }
714         case MONO_TYPE_TYPEDBYREF:
715                 inst->klass = mono_defaults.typed_reference_class;
716                 inst->type = STACK_VTYPE;
717                 return;
718         case MONO_TYPE_GENERICINST:
719                 type = &type->data.generic_class->container_class->byval_arg;
720                 goto handle_enum;
721         case MONO_TYPE_VAR:
722         case MONO_TYPE_MVAR:
723                 g_assert (cfg->generic_sharing_context);
724                 if (mini_is_gsharedvt_type (cfg, type)) {
725                         g_assert (cfg->gsharedvt);
726                         inst->type = STACK_VTYPE;
727                 } else {
728                         inst->type = STACK_OBJ;
729                 }
730                 return;
731         default:
732                 g_error ("unknown type 0x%02x in eval stack type", type->type);
733         }
734 }
735
736 /*
737  * The following tables are used to quickly validate the IL code in type_from_op ().
738  */
739 static const char
740 bin_num_table [STACK_MAX] [STACK_MAX] = {
741         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
742         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
743         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
744         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
745         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
746         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
747         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
748         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
749 };
750
751 static const char 
752 neg_table [] = {
753         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
754 };
755
756 /* reduce the size of this table */
757 static const char
758 bin_int_table [STACK_MAX] [STACK_MAX] = {
759         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
760         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
761         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
762         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
763         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
764         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
765         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
766         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
767 };
768
769 static const char
770 bin_comp_table [STACK_MAX] [STACK_MAX] = {
771 /*      Inv i  L  p  F  &  O  vt */
772         {0},
773         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
774         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
775         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
776         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
777         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
778         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
779         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
780 };
781
782 /* reduce the size of this table */
783 static const char
784 shift_table [STACK_MAX] [STACK_MAX] = {
785         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
786         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
787         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
788         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
789         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
790         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
791         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
792         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
793 };
794
795 /*
796  * Tables to map from the non-specific opcode to the matching
797  * type-specific opcode.
798  */
799 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
800 static const guint16
801 binops_op_map [STACK_MAX] = {
802         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
803 };
804
805 /* handles from CEE_NEG to CEE_CONV_U8 */
806 static const guint16
807 unops_op_map [STACK_MAX] = {
808         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
809 };
810
811 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
812 static const guint16
813 ovfops_op_map [STACK_MAX] = {
814         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
815 };
816
817 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
818 static const guint16
819 ovf2ops_op_map [STACK_MAX] = {
820         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
821 };
822
823 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
824 static const guint16
825 ovf3ops_op_map [STACK_MAX] = {
826         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
827 };
828
829 /* handles from CEE_BEQ to CEE_BLT_UN */
830 static const guint16
831 beqops_op_map [STACK_MAX] = {
832         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
833 };
834
835 /* handles from CEE_CEQ to CEE_CLT_UN */
836 static const guint16
837 ceqops_op_map [STACK_MAX] = {
838         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
839 };
840
841 /*
842  * Sets ins->type (the type on the eval stack) according to the
843  * type of the opcode and the arguments to it.
844  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
845  *
846  * FIXME: this function sets ins->type unconditionally in some cases, but
847  * it should set it to invalid for some types (a conv.x on an object)
848  */
849 static void
850 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
851
852         switch (ins->opcode) {
853         /* binops */
854         case CEE_ADD:
855         case CEE_SUB:
856         case CEE_MUL:
857         case CEE_DIV:
858         case CEE_REM:
859                 /* FIXME: check unverifiable args for STACK_MP */
860                 ins->type = bin_num_table [src1->type] [src2->type];
861                 ins->opcode += binops_op_map [ins->type];
862                 break;
863         case CEE_DIV_UN:
864         case CEE_REM_UN:
865         case CEE_AND:
866         case CEE_OR:
867         case CEE_XOR:
868                 ins->type = bin_int_table [src1->type] [src2->type];
869                 ins->opcode += binops_op_map [ins->type];
870                 break;
871         case CEE_SHL:
872         case CEE_SHR:
873         case CEE_SHR_UN:
874                 ins->type = shift_table [src1->type] [src2->type];
875                 ins->opcode += binops_op_map [ins->type];
876                 break;
877         case OP_COMPARE:
878         case OP_LCOMPARE:
879         case OP_ICOMPARE:
880                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
881                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
882                         ins->opcode = OP_LCOMPARE;
883                 else if (src1->type == STACK_R8)
884                         ins->opcode = OP_FCOMPARE;
885                 else
886                         ins->opcode = OP_ICOMPARE;
887                 break;
888         case OP_ICOMPARE_IMM:
889                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
890                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
891                         ins->opcode = OP_LCOMPARE_IMM;          
892                 break;
893         case CEE_BEQ:
894         case CEE_BGE:
895         case CEE_BGT:
896         case CEE_BLE:
897         case CEE_BLT:
898         case CEE_BNE_UN:
899         case CEE_BGE_UN:
900         case CEE_BGT_UN:
901         case CEE_BLE_UN:
902         case CEE_BLT_UN:
903                 ins->opcode += beqops_op_map [src1->type];
904                 break;
905         case OP_CEQ:
906                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
907                 ins->opcode += ceqops_op_map [src1->type];
908                 break;
909         case OP_CGT:
910         case OP_CGT_UN:
911         case OP_CLT:
912         case OP_CLT_UN:
913                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
914                 ins->opcode += ceqops_op_map [src1->type];
915                 break;
916         /* unops */
917         case CEE_NEG:
918                 ins->type = neg_table [src1->type];
919                 ins->opcode += unops_op_map [ins->type];
920                 break;
921         case CEE_NOT:
922                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
923                         ins->type = src1->type;
924                 else
925                         ins->type = STACK_INV;
926                 ins->opcode += unops_op_map [ins->type];
927                 break;
928         case CEE_CONV_I1:
929         case CEE_CONV_I2:
930         case CEE_CONV_I4:
931         case CEE_CONV_U4:
932                 ins->type = STACK_I4;
933                 ins->opcode += unops_op_map [src1->type];
934                 break;
935         case CEE_CONV_R_UN:
936                 ins->type = STACK_R8;
937                 switch (src1->type) {
938                 case STACK_I4:
939                 case STACK_PTR:
940                         ins->opcode = OP_ICONV_TO_R_UN;
941                         break;
942                 case STACK_I8:
943                         ins->opcode = OP_LCONV_TO_R_UN; 
944                         break;
945                 }
946                 break;
947         case CEE_CONV_OVF_I1:
948         case CEE_CONV_OVF_U1:
949         case CEE_CONV_OVF_I2:
950         case CEE_CONV_OVF_U2:
951         case CEE_CONV_OVF_I4:
952         case CEE_CONV_OVF_U4:
953                 ins->type = STACK_I4;
954                 ins->opcode += ovf3ops_op_map [src1->type];
955                 break;
956         case CEE_CONV_OVF_I_UN:
957         case CEE_CONV_OVF_U_UN:
958                 ins->type = STACK_PTR;
959                 ins->opcode += ovf2ops_op_map [src1->type];
960                 break;
961         case CEE_CONV_OVF_I1_UN:
962         case CEE_CONV_OVF_I2_UN:
963         case CEE_CONV_OVF_I4_UN:
964         case CEE_CONV_OVF_U1_UN:
965         case CEE_CONV_OVF_U2_UN:
966         case CEE_CONV_OVF_U4_UN:
967                 ins->type = STACK_I4;
968                 ins->opcode += ovf2ops_op_map [src1->type];
969                 break;
970         case CEE_CONV_U:
971                 ins->type = STACK_PTR;
972                 switch (src1->type) {
973                 case STACK_I4:
974                         ins->opcode = OP_ICONV_TO_U;
975                         break;
976                 case STACK_PTR:
977                 case STACK_MP:
978 #if SIZEOF_VOID_P == 8
979                         ins->opcode = OP_LCONV_TO_U;
980 #else
981                         ins->opcode = OP_MOVE;
982 #endif
983                         break;
984                 case STACK_I8:
985                         ins->opcode = OP_LCONV_TO_U;
986                         break;
987                 case STACK_R8:
988                         ins->opcode = OP_FCONV_TO_U;
989                         break;
990                 }
991                 break;
992         case CEE_CONV_I8:
993         case CEE_CONV_U8:
994                 ins->type = STACK_I8;
995                 ins->opcode += unops_op_map [src1->type];
996                 break;
997         case CEE_CONV_OVF_I8:
998         case CEE_CONV_OVF_U8:
999                 ins->type = STACK_I8;
1000                 ins->opcode += ovf3ops_op_map [src1->type];
1001                 break;
1002         case CEE_CONV_OVF_U8_UN:
1003         case CEE_CONV_OVF_I8_UN:
1004                 ins->type = STACK_I8;
1005                 ins->opcode += ovf2ops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R4:
1008         case CEE_CONV_R8:
1009                 ins->type = STACK_R8;
1010                 ins->opcode += unops_op_map [src1->type];
1011                 break;
1012         case OP_CKFINITE:
1013                 ins->type = STACK_R8;           
1014                 break;
1015         case CEE_CONV_U2:
1016         case CEE_CONV_U1:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += ovfops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_I:
1021         case CEE_CONV_OVF_I:
1022         case CEE_CONV_OVF_U:
1023                 ins->type = STACK_PTR;
1024                 ins->opcode += ovfops_op_map [src1->type];
1025                 break;
1026         case CEE_ADD_OVF:
1027         case CEE_ADD_OVF_UN:
1028         case CEE_MUL_OVF:
1029         case CEE_MUL_OVF_UN:
1030         case CEE_SUB_OVF:
1031         case CEE_SUB_OVF_UN:
1032                 ins->type = bin_num_table [src1->type] [src2->type];
1033                 ins->opcode += ovfops_op_map [src1->type];
1034                 if (ins->type == STACK_R8)
1035                         ins->type = STACK_INV;
1036                 break;
1037         case OP_LOAD_MEMBASE:
1038                 ins->type = STACK_PTR;
1039                 break;
1040         case OP_LOADI1_MEMBASE:
1041         case OP_LOADU1_MEMBASE:
1042         case OP_LOADI2_MEMBASE:
1043         case OP_LOADU2_MEMBASE:
1044         case OP_LOADI4_MEMBASE:
1045         case OP_LOADU4_MEMBASE:
1046                 ins->type = STACK_PTR;
1047                 break;
1048         case OP_LOADI8_MEMBASE:
1049                 ins->type = STACK_I8;
1050                 break;
1051         case OP_LOADR4_MEMBASE:
1052         case OP_LOADR8_MEMBASE:
1053                 ins->type = STACK_R8;
1054                 break;
1055         default:
1056                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1057                 break;
1058         }
1059
1060         if (ins->type == STACK_MP)
1061                 ins->klass = mono_defaults.object_class;
1062 }
1063
1064 static const char 
1065 ldind_type [] = {
1066         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1067 };
1068
1069 #if 0
1070
1071 static const char
1072 param_table [STACK_MAX] [STACK_MAX] = {
1073         {0},
1074 };
1075
1076 static int
1077 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1078         int i;
1079
1080         if (sig->hasthis) {
1081                 switch (args->type) {
1082                 case STACK_I4:
1083                 case STACK_I8:
1084                 case STACK_R8:
1085                 case STACK_VTYPE:
1086                 case STACK_INV:
1087                         return 0;
1088                 }
1089                 args++;
1090         }
1091         for (i = 0; i < sig->param_count; ++i) {
1092                 switch (args [i].type) {
1093                 case STACK_INV:
1094                         return 0;
1095                 case STACK_MP:
1096                         if (!sig->params [i]->byref)
1097                                 return 0;
1098                         continue;
1099                 case STACK_OBJ:
1100                         if (sig->params [i]->byref)
1101                                 return 0;
1102                         switch (sig->params [i]->type) {
1103                         case MONO_TYPE_CLASS:
1104                         case MONO_TYPE_STRING:
1105                         case MONO_TYPE_OBJECT:
1106                         case MONO_TYPE_SZARRAY:
1107                         case MONO_TYPE_ARRAY:
1108                                 break;
1109                         default:
1110                                 return 0;
1111                         }
1112                         continue;
1113                 case STACK_R8:
1114                         if (sig->params [i]->byref)
1115                                 return 0;
1116                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1117                                 return 0;
1118                         continue;
1119                 case STACK_PTR:
1120                 case STACK_I4:
1121                 case STACK_I8:
1122                 case STACK_VTYPE:
1123                         break;
1124                 }
1125                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1126                         return 0;*/
1127         }
1128         return 1;
1129 }
1130 #endif
1131
1132 /*
1133  * When we need a pointer to the current domain many times in a method, we
1134  * call mono_domain_get() once and we store the result in a local variable.
1135  * This function returns the variable that represents the MonoDomain*.
1136  */
1137 inline static MonoInst *
1138 mono_get_domainvar (MonoCompile *cfg)
1139 {
1140         if (!cfg->domainvar)
1141                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1142         return cfg->domainvar;
1143 }
1144
1145 /*
1146  * The got_var contains the address of the Global Offset Table when AOT 
1147  * compiling.
1148  */
1149 MonoInst *
1150 mono_get_got_var (MonoCompile *cfg)
1151 {
1152 #ifdef MONO_ARCH_NEED_GOT_VAR
1153         if (!cfg->compile_aot)
1154                 return NULL;
1155         if (!cfg->got_var) {
1156                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1157         }
1158         return cfg->got_var;
1159 #else
1160         return NULL;
1161 #endif
1162 }
1163
1164 static MonoInst *
1165 mono_get_vtable_var (MonoCompile *cfg)
1166 {
1167         g_assert (cfg->generic_sharing_context);
1168
1169         if (!cfg->rgctx_var) {
1170                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1171                 /* force the var to be stack allocated */
1172                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1173         }
1174
1175         return cfg->rgctx_var;
1176 }
1177
1178 static MonoType*
1179 type_from_stack_type (MonoInst *ins) {
1180         switch (ins->type) {
1181         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1182         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1183         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1184         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1185         case STACK_MP:
1186                 return &ins->klass->this_arg;
1187         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1188         case STACK_VTYPE: return &ins->klass->byval_arg;
1189         default:
1190                 g_error ("stack type %d to monotype not handled\n", ins->type);
1191         }
1192         return NULL;
1193 }
1194
1195 static G_GNUC_UNUSED int
1196 type_to_stack_type (MonoType *t)
1197 {
1198         t = mono_type_get_underlying_type (t);
1199         switch (t->type) {
1200         case MONO_TYPE_I1:
1201         case MONO_TYPE_U1:
1202         case MONO_TYPE_BOOLEAN:
1203         case MONO_TYPE_I2:
1204         case MONO_TYPE_U2:
1205         case MONO_TYPE_CHAR:
1206         case MONO_TYPE_I4:
1207         case MONO_TYPE_U4:
1208                 return STACK_I4;
1209         case MONO_TYPE_I:
1210         case MONO_TYPE_U:
1211         case MONO_TYPE_PTR:
1212         case MONO_TYPE_FNPTR:
1213                 return STACK_PTR;
1214         case MONO_TYPE_CLASS:
1215         case MONO_TYPE_STRING:
1216         case MONO_TYPE_OBJECT:
1217         case MONO_TYPE_SZARRAY:
1218         case MONO_TYPE_ARRAY:    
1219                 return STACK_OBJ;
1220         case MONO_TYPE_I8:
1221         case MONO_TYPE_U8:
1222                 return STACK_I8;
1223         case MONO_TYPE_R4:
1224         case MONO_TYPE_R8:
1225                 return STACK_R8;
1226         case MONO_TYPE_VALUETYPE:
1227         case MONO_TYPE_TYPEDBYREF:
1228                 return STACK_VTYPE;
1229         case MONO_TYPE_GENERICINST:
1230                 if (mono_type_generic_inst_is_valuetype (t))
1231                         return STACK_VTYPE;
1232                 else
1233                         return STACK_OBJ;
1234                 break;
1235         default:
1236                 g_assert_not_reached ();
1237         }
1238
1239         return -1;
1240 }
1241
1242 static MonoClass*
1243 array_access_to_klass (int opcode)
1244 {
1245         switch (opcode) {
1246         case CEE_LDELEM_U1:
1247                 return mono_defaults.byte_class;
1248         case CEE_LDELEM_U2:
1249                 return mono_defaults.uint16_class;
1250         case CEE_LDELEM_I:
1251         case CEE_STELEM_I:
1252                 return mono_defaults.int_class;
1253         case CEE_LDELEM_I1:
1254         case CEE_STELEM_I1:
1255                 return mono_defaults.sbyte_class;
1256         case CEE_LDELEM_I2:
1257         case CEE_STELEM_I2:
1258                 return mono_defaults.int16_class;
1259         case CEE_LDELEM_I4:
1260         case CEE_STELEM_I4:
1261                 return mono_defaults.int32_class;
1262         case CEE_LDELEM_U4:
1263                 return mono_defaults.uint32_class;
1264         case CEE_LDELEM_I8:
1265         case CEE_STELEM_I8:
1266                 return mono_defaults.int64_class;
1267         case CEE_LDELEM_R4:
1268         case CEE_STELEM_R4:
1269                 return mono_defaults.single_class;
1270         case CEE_LDELEM_R8:
1271         case CEE_STELEM_R8:
1272                 return mono_defaults.double_class;
1273         case CEE_LDELEM_REF:
1274         case CEE_STELEM_REF:
1275                 return mono_defaults.object_class;
1276         default:
1277                 g_assert_not_reached ();
1278         }
1279         return NULL;
1280 }
1281
1282 /*
1283  * We try to share variables when possible
1284  */
1285 static MonoInst *
1286 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1287 {
1288         MonoInst *res;
1289         int pos, vnum;
1290
1291         /* inlining can result in deeper stacks */ 
1292         if (slot >= cfg->header->max_stack)
1293                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1294
1295         pos = ins->type - 1 + slot * STACK_MAX;
1296
1297         switch (ins->type) {
1298         case STACK_I4:
1299         case STACK_I8:
1300         case STACK_R8:
1301         case STACK_PTR:
1302         case STACK_MP:
1303         case STACK_OBJ:
1304                 if ((vnum = cfg->intvars [pos]))
1305                         return cfg->varinfo [vnum];
1306                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1307                 cfg->intvars [pos] = res->inst_c0;
1308                 break;
1309         default:
1310                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1311         }
1312         return res;
1313 }
1314
1315 static void
1316 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1317 {
1318         /* 
1319          * Don't use this if a generic_context is set, since that means AOT can't
1320          * look up the method using just the image+token.
1321          * table == 0 means this is a reference made from a wrapper.
1322          */
1323         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1324                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1325                 jump_info_token->image = image;
1326                 jump_info_token->token = token;
1327                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1328         }
1329 }
1330
1331 /*
1332  * This function is called to handle items that are left on the evaluation stack
1333  * at basic block boundaries. What happens is that we save the values to local variables
1334  * and we reload them later when first entering the target basic block (with the
1335  * handle_loaded_temps () function).
1336  * A single joint point will use the same variables (stored in the array bb->out_stack or
1337  * bb->in_stack, if the basic block is before or after the joint point).
1338  *
1339  * This function needs to be called _before_ emitting the last instruction of
1340  * the bb (i.e. before emitting a branch).
1341  * If the stack merge fails at a join point, cfg->unverifiable is set.
1342  */
1343 static void
1344 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1345 {
1346         int i, bindex;
1347         MonoBasicBlock *bb = cfg->cbb;
1348         MonoBasicBlock *outb;
1349         MonoInst *inst, **locals;
1350         gboolean found;
1351
1352         if (!count)
1353                 return;
1354         if (cfg->verbose_level > 3)
1355                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1356         if (!bb->out_scount) {
1357                 bb->out_scount = count;
1358                 //printf ("bblock %d has out:", bb->block_num);
1359                 found = FALSE;
1360                 for (i = 0; i < bb->out_count; ++i) {
1361                         outb = bb->out_bb [i];
1362                         /* exception handlers are linked, but they should not be considered for stack args */
1363                         if (outb->flags & BB_EXCEPTION_HANDLER)
1364                                 continue;
1365                         //printf (" %d", outb->block_num);
1366                         if (outb->in_stack) {
1367                                 found = TRUE;
1368                                 bb->out_stack = outb->in_stack;
1369                                 break;
1370                         }
1371                 }
1372                 //printf ("\n");
1373                 if (!found) {
1374                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1375                         for (i = 0; i < count; ++i) {
1376                                 /* 
1377                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1378                                  * stack slot and if they are of the same type.
1379                                  * This won't cause conflicts since if 'local' is used to 
1380                                  * store one of the values in the in_stack of a bblock, then
1381                                  * the same variable will be used for the same outgoing stack 
1382                                  * slot as well. 
1383                                  * This doesn't work when inlining methods, since the bblocks
1384                                  * in the inlined methods do not inherit their in_stack from
1385                                  * the bblock they are inlined to. See bug #58863 for an
1386                                  * example.
1387                                  */
1388                                 if (cfg->inlined_method)
1389                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1390                                 else
1391                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1392                         }
1393                 }
1394         }
1395
1396         for (i = 0; i < bb->out_count; ++i) {
1397                 outb = bb->out_bb [i];
1398                 /* exception handlers are linked, but they should not be considered for stack args */
1399                 if (outb->flags & BB_EXCEPTION_HANDLER)
1400                         continue;
1401                 if (outb->in_scount) {
1402                         if (outb->in_scount != bb->out_scount) {
1403                                 cfg->unverifiable = TRUE;
1404                                 return;
1405                         }
1406                         continue; /* check they are the same locals */
1407                 }
1408                 outb->in_scount = count;
1409                 outb->in_stack = bb->out_stack;
1410         }
1411
1412         locals = bb->out_stack;
1413         cfg->cbb = bb;
1414         for (i = 0; i < count; ++i) {
1415                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1416                 inst->cil_code = sp [i]->cil_code;
1417                 sp [i] = locals [i];
1418                 if (cfg->verbose_level > 3)
1419                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1420         }
1421
1422         /*
1423          * It is possible that the out bblocks already have in_stack assigned, and
1424          * the in_stacks differ. In this case, we will store to all the different 
1425          * in_stacks.
1426          */
1427
1428         found = TRUE;
1429         bindex = 0;
1430         while (found) {
1431                 /* Find a bblock which has a different in_stack */
1432                 found = FALSE;
1433                 while (bindex < bb->out_count) {
1434                         outb = bb->out_bb [bindex];
1435                         /* exception handlers are linked, but they should not be considered for stack args */
1436                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1437                                 bindex++;
1438                                 continue;
1439                         }
1440                         if (outb->in_stack != locals) {
1441                                 for (i = 0; i < count; ++i) {
1442                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1443                                         inst->cil_code = sp [i]->cil_code;
1444                                         sp [i] = locals [i];
1445                                         if (cfg->verbose_level > 3)
1446                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1447                                 }
1448                                 locals = outb->in_stack;
1449                                 found = TRUE;
1450                                 break;
1451                         }
1452                         bindex ++;
1453                 }
1454         }
1455 }
1456
1457 /* Emit code which loads interface_offsets [klass->interface_id]
1458  * The array is stored in memory before vtable.
1459 */
1460 static void
1461 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1462 {
1463         if (cfg->compile_aot) {
1464                 int ioffset_reg = alloc_preg (cfg);
1465                 int iid_reg = alloc_preg (cfg);
1466
1467                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1468                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1469                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1470         }
1471         else {
1472                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1473         }
1474 }
1475
1476 static void
1477 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1478 {
1479         int ibitmap_reg = alloc_preg (cfg);
1480 #ifdef COMPRESSED_INTERFACE_BITMAP
1481         MonoInst *args [2];
1482         MonoInst *res, *ins;
1483         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1484         MONO_ADD_INS (cfg->cbb, ins);
1485         args [0] = ins;
1486         if (cfg->compile_aot)
1487                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1488         else
1489                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1490         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1491         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1492 #else
1493         int ibitmap_byte_reg = alloc_preg (cfg);
1494
1495         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1496
1497         if (cfg->compile_aot) {
1498                 int iid_reg = alloc_preg (cfg);
1499                 int shifted_iid_reg = alloc_preg (cfg);
1500                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1501                 int masked_iid_reg = alloc_preg (cfg);
1502                 int iid_one_bit_reg = alloc_preg (cfg);
1503                 int iid_bit_reg = alloc_preg (cfg);
1504                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1505                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1506                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1507                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1508                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1509                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1510                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1511                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1512         } else {
1513                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1514                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1515         }
1516 #endif
1517 }
1518
1519 /* 
1520  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1521  * stored in "klass_reg" implements the interface "klass".
1522  */
1523 static void
1524 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1525 {
1526         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1527 }
1528
1529 /* 
1530  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1531  * stored in "vtable_reg" implements the interface "klass".
1532  */
1533 static void
1534 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1535 {
1536         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1537 }
1538
1539 /* 
1540  * Emit code which checks whenever the interface id of @klass is smaller than
1541  * than the value given by max_iid_reg.
1542 */
1543 static void
1544 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1545                                                  MonoBasicBlock *false_target)
1546 {
1547         if (cfg->compile_aot) {
1548                 int iid_reg = alloc_preg (cfg);
1549                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1550                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1551         }
1552         else
1553                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1554         if (false_target)
1555                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1556         else
1557                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1558 }
1559
1560 /* Same as above, but obtains max_iid from a vtable */
1561 static void
1562 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1563                                                                  MonoBasicBlock *false_target)
1564 {
1565         int max_iid_reg = alloc_preg (cfg);
1566                 
1567         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1568         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1569 }
1570
1571 /* Same as above, but obtains max_iid from a klass */
1572 static void
1573 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1574                                                                  MonoBasicBlock *false_target)
1575 {
1576         int max_iid_reg = alloc_preg (cfg);
1577
1578         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1579         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1580 }
1581
1582 static void
1583 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1584 {
1585         int idepth_reg = alloc_preg (cfg);
1586         int stypes_reg = alloc_preg (cfg);
1587         int stype = alloc_preg (cfg);
1588
1589         mono_class_setup_supertypes (klass);
1590
1591         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1592                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1593                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1594                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1595         }
1596         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1597         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1598         if (klass_ins) {
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1600         } else if (cfg->compile_aot) {
1601                 int const_reg = alloc_preg (cfg);
1602                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1604         } else {
1605                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1606         }
1607         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1608 }
1609
1610 static void
1611 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1612 {
1613         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1614 }
1615
1616 static void
1617 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1618 {
1619         int intf_reg = alloc_preg (cfg);
1620
1621         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1622         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1623         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1624         if (true_target)
1625                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1626         else
1627                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1628 }
1629
1630 /*
1631  * Variant of the above that takes a register to the class, not the vtable.
1632  */
1633 static void
1634 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1635 {
1636         int intf_bit_reg = alloc_preg (cfg);
1637
1638         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1639         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1640         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1641         if (true_target)
1642                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1643         else
1644                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1645 }
1646
1647 static inline void
1648 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1649 {
1650         if (klass_inst) {
1651                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1652         } else if (cfg->compile_aot) {
1653                 int const_reg = alloc_preg (cfg);
1654                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1655                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1656         } else {
1657                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1658         }
1659         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1660 }
1661
1662 static inline void
1663 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1664 {
1665         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1666 }
1667
1668 static inline void
1669 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1670 {
1671         if (cfg->compile_aot) {
1672                 int const_reg = alloc_preg (cfg);
1673                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1674                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1675         } else {
1676                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1677         }
1678         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1679 }
1680
1681 static void
1682 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1683         
1684 static void
1685 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1686 {
1687         if (klass->rank) {
1688                 int rank_reg = alloc_preg (cfg);
1689                 int eclass_reg = alloc_preg (cfg);
1690
1691                 g_assert (!klass_inst);
1692                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1693                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1694                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1695                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1696                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1697                 if (klass->cast_class == mono_defaults.object_class) {
1698                         int parent_reg = alloc_preg (cfg);
1699                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1700                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1701                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1702                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1703                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1704                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1705                 } else if (klass->cast_class == mono_defaults.enum_class) {
1706                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1707                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1708                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1709                 } else {
1710                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1711                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1712                 }
1713
1714                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1715                         /* Check that the object is a vector too */
1716                         int bounds_reg = alloc_preg (cfg);
1717                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1718                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1719                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1720                 }
1721         } else {
1722                 int idepth_reg = alloc_preg (cfg);
1723                 int stypes_reg = alloc_preg (cfg);
1724                 int stype = alloc_preg (cfg);
1725
1726                 mono_class_setup_supertypes (klass);
1727
1728                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1729                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1730                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1731                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1732                 }
1733                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1734                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1735                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1736         }
1737 }
1738
1739 static void
1740 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1741 {
1742         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1743 }
1744
1745 static void 
1746 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1747 {
1748         int val_reg;
1749
1750         g_assert (val == 0);
1751
1752         if (align == 0)
1753                 align = 4;
1754
1755         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1756                 switch (size) {
1757                 case 1:
1758                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1759                         return;
1760                 case 2:
1761                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1762                         return;
1763                 case 4:
1764                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1765                         return;
1766 #if SIZEOF_REGISTER == 8
1767                 case 8:
1768                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1769                         return;
1770 #endif
1771                 }
1772         }
1773
1774         val_reg = alloc_preg (cfg);
1775
1776         if (SIZEOF_REGISTER == 8)
1777                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1778         else
1779                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1780
1781         if (align < 4) {
1782                 /* This could be optimized further if neccesary */
1783                 while (size >= 1) {
1784                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1785                         offset += 1;
1786                         size -= 1;
1787                 }
1788                 return;
1789         }       
1790
1791 #if !NO_UNALIGNED_ACCESS
1792         if (SIZEOF_REGISTER == 8) {
1793                 if (offset % 8) {
1794                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1795                         offset += 4;
1796                         size -= 4;
1797                 }
1798                 while (size >= 8) {
1799                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1800                         offset += 8;
1801                         size -= 8;
1802                 }
1803         }       
1804 #endif
1805
1806         while (size >= 4) {
1807                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1808                 offset += 4;
1809                 size -= 4;
1810         }
1811         while (size >= 2) {
1812                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1813                 offset += 2;
1814                 size -= 2;
1815         }
1816         while (size >= 1) {
1817                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1818                 offset += 1;
1819                 size -= 1;
1820         }
1821 }
1822
1823 void 
1824 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1825 {
1826         int cur_reg;
1827
1828         if (align == 0)
1829                 align = 4;
1830
1831         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1832         g_assert (size < 10000);
1833
1834         if (align < 4) {
1835                 /* This could be optimized further if neccesary */
1836                 while (size >= 1) {
1837                         cur_reg = alloc_preg (cfg);
1838                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1839                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1840                         doffset += 1;
1841                         soffset += 1;
1842                         size -= 1;
1843                 }
1844         }
1845
1846 #if !NO_UNALIGNED_ACCESS
1847         if (SIZEOF_REGISTER == 8) {
1848                 while (size >= 8) {
1849                         cur_reg = alloc_preg (cfg);
1850                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1851                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1852                         doffset += 8;
1853                         soffset += 8;
1854                         size -= 8;
1855                 }
1856         }       
1857 #endif
1858
1859         while (size >= 4) {
1860                 cur_reg = alloc_preg (cfg);
1861                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1862                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1863                 doffset += 4;
1864                 soffset += 4;
1865                 size -= 4;
1866         }
1867         while (size >= 2) {
1868                 cur_reg = alloc_preg (cfg);
1869                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1870                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1871                 doffset += 2;
1872                 soffset += 2;
1873                 size -= 2;
1874         }
1875         while (size >= 1) {
1876                 cur_reg = alloc_preg (cfg);
1877                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1878                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1879                 doffset += 1;
1880                 soffset += 1;
1881                 size -= 1;
1882         }
1883 }
1884
1885 static void
1886 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1887 {
1888         MonoInst *ins, *c;
1889
1890         if (cfg->compile_aot) {
1891                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1892                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1893                 ins->sreg1 = sreg1;
1894                 ins->sreg2 = c->dreg;
1895                 MONO_ADD_INS (cfg->cbb, ins);
1896         } else {
1897                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1898                 ins->sreg1 = sreg1;
1899                 ins->inst_offset = mini_get_tls_offset (tls_key);
1900                 MONO_ADD_INS (cfg->cbb, ins);
1901         }
1902 }
1903
1904 /*
1905  * emit_push_lmf:
1906  *
1907  *   Emit IR to push the current LMF onto the LMF stack.
1908  */
1909 static void
1910 emit_push_lmf (MonoCompile *cfg)
1911 {
1912         /*
1913          * Emit IR to push the LMF:
1914          * lmf_addr = <lmf_addr from tls>
1915          * lmf->lmf_addr = lmf_addr
1916          * lmf->prev_lmf = *lmf_addr
1917          * *lmf_addr = lmf
1918          */
1919         int lmf_reg, prev_lmf_reg;
1920         MonoInst *ins, *lmf_ins;
1921
1922         if (!cfg->lmf_ir)
1923                 return;
1924
1925         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1926                 /* Load current lmf */
1927                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1928                 g_assert (lmf_ins);
1929                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1930                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1931                 lmf_reg = ins->dreg;
1932                 /* Save previous_lmf */
1933                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1934                 /* Set new LMF */
1935                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1936         } else {
1937                 /*
1938                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1939                  */
1940                 if (!cfg->lmf_addr_var)
1941                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1942
1943 #ifdef HOST_WIN32
1944                 ins = mono_get_jit_tls_intrinsic (cfg);
1945                 if (ins) {
1946                         int jit_tls_dreg = ins->dreg;
1947
1948                         MONO_ADD_INS (cfg->cbb, ins);
1949                         lmf_reg = alloc_preg (cfg);
1950                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
1951                 } else {
1952                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1953                 }
1954 #else
1955                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1956                 if (lmf_ins) {
1957                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1958                 } else {
1959 #ifdef TARGET_IOS
1960                         MonoInst *args [16], *jit_tls_ins, *ins;
1961
1962                         /* Inline mono_get_lmf_addr () */
1963                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
1964
1965                         /* Load mono_jit_tls_id */
1966                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
1967                         /* call pthread_getspecific () */
1968                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
1969                         /* lmf_addr = &jit_tls->lmf */
1970                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
1971                         lmf_ins = ins;
1972 #else
1973                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1974 #endif
1975                 }
1976 #endif
1977                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1978
1979                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1980                 lmf_reg = ins->dreg;
1981
1982                 prev_lmf_reg = alloc_preg (cfg);
1983                 /* Save previous_lmf */
1984                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1985                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1986                 /* Set new lmf */
1987                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1988         }
1989 }
1990
1991 /*
1992  * emit_pop_lmf:
1993  *
1994  *   Emit IR to pop the current LMF from the LMF stack.
1995  */
1996 static void
1997 emit_pop_lmf (MonoCompile *cfg)
1998 {
1999         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2000         MonoInst *ins;
2001
2002         if (!cfg->lmf_ir)
2003                 return;
2004
2005         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2006         lmf_reg = ins->dreg;
2007
2008         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2009                 /* Load previous_lmf */
2010                 prev_lmf_reg = alloc_preg (cfg);
2011                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2012                 /* Set new LMF */
2013                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2014         } else {
2015                 /*
2016                  * Emit IR to pop the LMF:
2017                  * *(lmf->lmf_addr) = lmf->prev_lmf
2018                  */
2019                 /* This could be called before emit_push_lmf () */
2020                 if (!cfg->lmf_addr_var)
2021                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2022                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2023
2024                 prev_lmf_reg = alloc_preg (cfg);
2025                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2026                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2027         }
2028 }
2029
2030 static int
2031 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2032 {
2033         if (type->byref)
2034                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2035
2036 handle_enum:
2037         type = mini_get_basic_type_from_generic (gsctx, type);
2038         type = mini_replace_type (type);
2039         switch (type->type) {
2040         case MONO_TYPE_VOID:
2041                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2042         case MONO_TYPE_I1:
2043         case MONO_TYPE_U1:
2044         case MONO_TYPE_BOOLEAN:
2045         case MONO_TYPE_I2:
2046         case MONO_TYPE_U2:
2047         case MONO_TYPE_CHAR:
2048         case MONO_TYPE_I4:
2049         case MONO_TYPE_U4:
2050                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2051         case MONO_TYPE_I:
2052         case MONO_TYPE_U:
2053         case MONO_TYPE_PTR:
2054         case MONO_TYPE_FNPTR:
2055                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2056         case MONO_TYPE_CLASS:
2057         case MONO_TYPE_STRING:
2058         case MONO_TYPE_OBJECT:
2059         case MONO_TYPE_SZARRAY:
2060         case MONO_TYPE_ARRAY:    
2061                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2062         case MONO_TYPE_I8:
2063         case MONO_TYPE_U8:
2064                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2065         case MONO_TYPE_R4:
2066         case MONO_TYPE_R8:
2067                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2068         case MONO_TYPE_VALUETYPE:
2069                 if (type->data.klass->enumtype) {
2070                         type = mono_class_enum_basetype (type->data.klass);
2071                         goto handle_enum;
2072                 } else
2073                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2074         case MONO_TYPE_TYPEDBYREF:
2075                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2076         case MONO_TYPE_GENERICINST:
2077                 type = &type->data.generic_class->container_class->byval_arg;
2078                 goto handle_enum;
2079         case MONO_TYPE_VAR:
2080         case MONO_TYPE_MVAR:
2081                 /* gsharedvt */
2082                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2083         default:
2084                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2085         }
2086         return -1;
2087 }
2088
2089 /*
2090  * target_type_is_incompatible:
2091  * @cfg: MonoCompile context
2092  *
2093  * Check that the item @arg on the evaluation stack can be stored
2094  * in the target type (can be a local, or field, etc).
2095  * The cfg arg can be used to check if we need verification or just
2096  * validity checks.
2097  *
2098  * Returns: non-0 value if arg can't be stored on a target.
2099  */
2100 static int
2101 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2102 {
2103         MonoType *simple_type;
2104         MonoClass *klass;
2105
2106         target = mini_replace_type (target);
2107         if (target->byref) {
2108                 /* FIXME: check that the pointed to types match */
2109                 if (arg->type == STACK_MP)
2110                         return arg->klass != mono_class_from_mono_type (target);
2111                 if (arg->type == STACK_PTR)
2112                         return 0;
2113                 return 1;
2114         }
2115
2116         simple_type = mono_type_get_underlying_type (target);
2117         switch (simple_type->type) {
2118         case MONO_TYPE_VOID:
2119                 return 1;
2120         case MONO_TYPE_I1:
2121         case MONO_TYPE_U1:
2122         case MONO_TYPE_BOOLEAN:
2123         case MONO_TYPE_I2:
2124         case MONO_TYPE_U2:
2125         case MONO_TYPE_CHAR:
2126         case MONO_TYPE_I4:
2127         case MONO_TYPE_U4:
2128                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2129                         return 1;
2130                 return 0;
2131         case MONO_TYPE_PTR:
2132                 /* STACK_MP is needed when setting pinned locals */
2133                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2134                         return 1;
2135                 return 0;
2136         case MONO_TYPE_I:
2137         case MONO_TYPE_U:
2138         case MONO_TYPE_FNPTR:
2139                 /* 
2140                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2141                  * in native int. (#688008).
2142                  */
2143                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2144                         return 1;
2145                 return 0;
2146         case MONO_TYPE_CLASS:
2147         case MONO_TYPE_STRING:
2148         case MONO_TYPE_OBJECT:
2149         case MONO_TYPE_SZARRAY:
2150         case MONO_TYPE_ARRAY:    
2151                 if (arg->type != STACK_OBJ)
2152                         return 1;
2153                 /* FIXME: check type compatibility */
2154                 return 0;
2155         case MONO_TYPE_I8:
2156         case MONO_TYPE_U8:
2157                 if (arg->type != STACK_I8)
2158                         return 1;
2159                 return 0;
2160         case MONO_TYPE_R4:
2161         case MONO_TYPE_R8:
2162                 if (arg->type != STACK_R8)
2163                         return 1;
2164                 return 0;
2165         case MONO_TYPE_VALUETYPE:
2166                 if (arg->type != STACK_VTYPE)
2167                         return 1;
2168                 klass = mono_class_from_mono_type (simple_type);
2169                 if (klass != arg->klass)
2170                         return 1;
2171                 return 0;
2172         case MONO_TYPE_TYPEDBYREF:
2173                 if (arg->type != STACK_VTYPE)
2174                         return 1;
2175                 klass = mono_class_from_mono_type (simple_type);
2176                 if (klass != arg->klass)
2177                         return 1;
2178                 return 0;
2179         case MONO_TYPE_GENERICINST:
2180                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2181                         if (arg->type != STACK_VTYPE)
2182                                 return 1;
2183                         klass = mono_class_from_mono_type (simple_type);
2184                         if (klass != arg->klass)
2185                                 return 1;
2186                         return 0;
2187                 } else {
2188                         if (arg->type != STACK_OBJ)
2189                                 return 1;
2190                         /* FIXME: check type compatibility */
2191                         return 0;
2192                 }
2193         case MONO_TYPE_VAR:
2194         case MONO_TYPE_MVAR:
2195                 g_assert (cfg->generic_sharing_context);
2196                 if (mini_type_var_is_vt (cfg, simple_type)) {
2197                         if (arg->type != STACK_VTYPE)
2198                                 return 1;
2199                 } else {
2200                         if (arg->type != STACK_OBJ)
2201                                 return 1;
2202                 }
2203                 return 0;
2204         default:
2205                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2206         }
2207         return 1;
2208 }
2209
2210 /*
2211  * Prepare arguments for passing to a function call.
2212  * Return a non-zero value if the arguments can't be passed to the given
2213  * signature.
2214  * The type checks are not yet complete and some conversions may need
2215  * casts on 32 or 64 bit architectures.
2216  *
2217  * FIXME: implement this using target_type_is_incompatible ()
2218  */
2219 static int
2220 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2221 {
2222         MonoType *simple_type;
2223         int i;
2224
2225         if (sig->hasthis) {
2226                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2227                         return 1;
2228                 args++;
2229         }
2230         for (i = 0; i < sig->param_count; ++i) {
2231                 if (sig->params [i]->byref) {
2232                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2233                                 return 1;
2234                         continue;
2235                 }
2236                 simple_type = sig->params [i];
2237                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2238 handle_enum:
2239                 switch (simple_type->type) {
2240                 case MONO_TYPE_VOID:
2241                         return 1;
2242                         continue;
2243                 case MONO_TYPE_I1:
2244                 case MONO_TYPE_U1:
2245                 case MONO_TYPE_BOOLEAN:
2246                 case MONO_TYPE_I2:
2247                 case MONO_TYPE_U2:
2248                 case MONO_TYPE_CHAR:
2249                 case MONO_TYPE_I4:
2250                 case MONO_TYPE_U4:
2251                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2252                                 return 1;
2253                         continue;
2254                 case MONO_TYPE_I:
2255                 case MONO_TYPE_U:
2256                 case MONO_TYPE_PTR:
2257                 case MONO_TYPE_FNPTR:
2258                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2259                                 return 1;
2260                         continue;
2261                 case MONO_TYPE_CLASS:
2262                 case MONO_TYPE_STRING:
2263                 case MONO_TYPE_OBJECT:
2264                 case MONO_TYPE_SZARRAY:
2265                 case MONO_TYPE_ARRAY:    
2266                         if (args [i]->type != STACK_OBJ)
2267                                 return 1;
2268                         continue;
2269                 case MONO_TYPE_I8:
2270                 case MONO_TYPE_U8:
2271                         if (args [i]->type != STACK_I8)
2272                                 return 1;
2273                         continue;
2274                 case MONO_TYPE_R4:
2275                 case MONO_TYPE_R8:
2276                         if (args [i]->type != STACK_R8)
2277                                 return 1;
2278                         continue;
2279                 case MONO_TYPE_VALUETYPE:
2280                         if (simple_type->data.klass->enumtype) {
2281                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2282                                 goto handle_enum;
2283                         }
2284                         if (args [i]->type != STACK_VTYPE)
2285                                 return 1;
2286                         continue;
2287                 case MONO_TYPE_TYPEDBYREF:
2288                         if (args [i]->type != STACK_VTYPE)
2289                                 return 1;
2290                         continue;
2291                 case MONO_TYPE_GENERICINST:
2292                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2293                         goto handle_enum;
2294                 case MONO_TYPE_VAR:
2295                 case MONO_TYPE_MVAR:
2296                         /* gsharedvt */
2297                         if (args [i]->type != STACK_VTYPE)
2298                                 return 1;
2299                         continue;
2300                 default:
2301                         g_error ("unknown type 0x%02x in check_call_signature",
2302                                  simple_type->type);
2303                 }
2304         }
2305         return 0;
2306 }
2307
2308 static int
2309 callvirt_to_call (int opcode)
2310 {
2311         switch (opcode) {
2312         case OP_CALL_MEMBASE:
2313                 return OP_CALL;
2314         case OP_VOIDCALL_MEMBASE:
2315                 return OP_VOIDCALL;
2316         case OP_FCALL_MEMBASE:
2317                 return OP_FCALL;
2318         case OP_VCALL_MEMBASE:
2319                 return OP_VCALL;
2320         case OP_LCALL_MEMBASE:
2321                 return OP_LCALL;
2322         default:
2323                 g_assert_not_reached ();
2324         }
2325
2326         return -1;
2327 }
2328
2329 #ifdef MONO_ARCH_HAVE_IMT
2330 /* Either METHOD or IMT_ARG needs to be set */
2331 static void
2332 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2333 {
2334         int method_reg;
2335
2336         if (COMPILE_LLVM (cfg)) {
2337                 method_reg = alloc_preg (cfg);
2338
2339                 if (imt_arg) {
2340                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2341                 } else if (cfg->compile_aot) {
2342                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2343                 } else {
2344                         MonoInst *ins;
2345                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2346                         ins->inst_p0 = method;
2347                         ins->dreg = method_reg;
2348                         MONO_ADD_INS (cfg->cbb, ins);
2349                 }
2350
2351 #ifdef ENABLE_LLVM
2352                 call->imt_arg_reg = method_reg;
2353 #endif
2354 #ifdef MONO_ARCH_IMT_REG
2355         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2356 #else
2357         /* Need this to keep the IMT arg alive */
2358         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2359 #endif
2360                 return;
2361         }
2362
2363 #ifdef MONO_ARCH_IMT_REG
2364         method_reg = alloc_preg (cfg);
2365
2366         if (imt_arg) {
2367                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2368         } else if (cfg->compile_aot) {
2369                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2370         } else {
2371                 MonoInst *ins;
2372                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2373                 ins->inst_p0 = method;
2374                 ins->dreg = method_reg;
2375                 MONO_ADD_INS (cfg->cbb, ins);
2376         }
2377
2378         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2379 #else
2380         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2381 #endif
2382 }
2383 #endif
2384
2385 static MonoJumpInfo *
2386 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2387 {
2388         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2389
2390         ji->ip.i = ip;
2391         ji->type = type;
2392         ji->data.target = target;
2393
2394         return ji;
2395 }
2396
2397 static int
2398 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2399 {
2400         if (cfg->generic_sharing_context)
2401                 return mono_class_check_context_used (klass);
2402         else
2403                 return 0;
2404 }
2405
2406 static int
2407 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2408 {
2409         if (cfg->generic_sharing_context)
2410                 return mono_method_check_context_used (method);
2411         else
2412                 return 0;
2413 }
2414
2415 /*
2416  * check_method_sharing:
2417  *
2418  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2419  */
2420 static void
2421 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2422 {
2423         gboolean pass_vtable = FALSE;
2424         gboolean pass_mrgctx = FALSE;
2425
2426         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2427                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2428                 gboolean sharable = FALSE;
2429
2430                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2431                         sharable = TRUE;
2432                 } else {
2433                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2434                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2435                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2436
2437                         sharable = sharing_enabled && context_sharable;
2438                 }
2439
2440                 /*
2441                  * Pass vtable iff target method might
2442                  * be shared, which means that sharing
2443                  * is enabled for its class and its
2444                  * context is sharable (and it's not a
2445                  * generic method).
2446                  */
2447                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2448                         pass_vtable = TRUE;
2449         }
2450
2451         if (mini_method_get_context (cmethod) &&
2452                 mini_method_get_context (cmethod)->method_inst) {
2453                 g_assert (!pass_vtable);
2454
2455                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2456                         pass_mrgctx = TRUE;
2457                 } else {
2458                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2459                         MonoGenericContext *context = mini_method_get_context (cmethod);
2460                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2461
2462                         if (sharing_enabled && context_sharable)
2463                                 pass_mrgctx = TRUE;
2464                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2465                                 pass_mrgctx = TRUE;
2466                 }
2467         }
2468
2469         if (out_pass_vtable)
2470                 *out_pass_vtable = pass_vtable;
2471         if (out_pass_mrgctx)
2472                 *out_pass_mrgctx = pass_mrgctx;
2473 }
2474
2475 inline static MonoCallInst *
2476 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2477                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2478 {
2479         MonoType *sig_ret;
2480         MonoCallInst *call;
2481 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2482         int i;
2483 #endif
2484
2485         if (tail)
2486                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2487         else
2488                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2489
2490         call->args = args;
2491         call->signature = sig;
2492         call->rgctx_reg = rgctx;
2493         sig_ret = mini_replace_type (sig->ret);
2494
2495         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2496
2497         if (tail) {
2498                 if (mini_type_is_vtype (cfg, sig_ret)) {
2499                         call->vret_var = cfg->vret_addr;
2500                         //g_assert_not_reached ();
2501                 }
2502         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2503                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2504                 MonoInst *loada;
2505
2506                 temp->backend.is_pinvoke = sig->pinvoke;
2507
2508                 /*
2509                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2510                  * address of return value to increase optimization opportunities.
2511                  * Before vtype decomposition, the dreg of the call ins itself represents the
2512                  * fact the call modifies the return value. After decomposition, the call will
2513                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2514                  * will be transformed into an LDADDR.
2515                  */
2516                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2517                 loada->dreg = alloc_preg (cfg);
2518                 loada->inst_p0 = temp;
2519                 /* We reference the call too since call->dreg could change during optimization */
2520                 loada->inst_p1 = call;
2521                 MONO_ADD_INS (cfg->cbb, loada);
2522
2523                 call->inst.dreg = temp->dreg;
2524
2525                 call->vret_var = loada;
2526         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2527                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2528
2529 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2530         if (COMPILE_SOFT_FLOAT (cfg)) {
2531                 /* 
2532                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2533                  * an icall, but that cannot be done during the call sequence since it would clobber
2534                  * the call registers + the stack. So we do it before emitting the call.
2535                  */
2536                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2537                         MonoType *t;
2538                         MonoInst *in = call->args [i];
2539
2540                         if (i >= sig->hasthis)
2541                                 t = sig->params [i - sig->hasthis];
2542                         else
2543                                 t = &mono_defaults.int_class->byval_arg;
2544                         t = mono_type_get_underlying_type (t);
2545
2546                         if (!t->byref && t->type == MONO_TYPE_R4) {
2547                                 MonoInst *iargs [1];
2548                                 MonoInst *conv;
2549
2550                                 iargs [0] = in;
2551                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2552
2553                                 /* The result will be in an int vreg */
2554                                 call->args [i] = conv;
2555                         }
2556                 }
2557         }
2558 #endif
2559
2560         call->need_unbox_trampoline = unbox_trampoline;
2561
2562 #ifdef ENABLE_LLVM
2563         if (COMPILE_LLVM (cfg))
2564                 mono_llvm_emit_call (cfg, call);
2565         else
2566                 mono_arch_emit_call (cfg, call);
2567 #else
2568         mono_arch_emit_call (cfg, call);
2569 #endif
2570
2571         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2572         cfg->flags |= MONO_CFG_HAS_CALLS;
2573         
2574         return call;
2575 }
2576
2577 static void
2578 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2579 {
2580 #ifdef MONO_ARCH_RGCTX_REG
2581         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2582         cfg->uses_rgctx_reg = TRUE;
2583         call->rgctx_reg = TRUE;
2584 #ifdef ENABLE_LLVM
2585         call->rgctx_arg_reg = rgctx_reg;
2586 #endif
2587 #else
2588         NOT_IMPLEMENTED;
2589 #endif
2590 }       
2591
2592 inline static MonoInst*
2593 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2594 {
2595         MonoCallInst *call;
2596         MonoInst *ins;
2597         int rgctx_reg = -1;
2598         gboolean check_sp = FALSE;
2599
2600         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2601                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2602
2603                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2604                         check_sp = TRUE;
2605         }
2606
2607         if (rgctx_arg) {
2608                 rgctx_reg = mono_alloc_preg (cfg);
2609                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2610         }
2611
2612         if (check_sp) {
2613                 if (!cfg->stack_inbalance_var)
2614                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2615
2616                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2617                 ins->dreg = cfg->stack_inbalance_var->dreg;
2618                 MONO_ADD_INS (cfg->cbb, ins);
2619         }
2620
2621         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2622
2623         call->inst.sreg1 = addr->dreg;
2624
2625         if (imt_arg)
2626                 emit_imt_argument (cfg, call, NULL, imt_arg);
2627
2628         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2629
2630         if (check_sp) {
2631                 int sp_reg;
2632
2633                 sp_reg = mono_alloc_preg (cfg);
2634
2635                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2636                 ins->dreg = sp_reg;
2637                 MONO_ADD_INS (cfg->cbb, ins);
2638
2639                 /* Restore the stack so we don't crash when throwing the exception */
2640                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2641                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2642                 MONO_ADD_INS (cfg->cbb, ins);
2643
2644                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2645                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2646         }
2647
2648         if (rgctx_arg)
2649                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2650
2651         return (MonoInst*)call;
2652 }
2653
2654 static MonoInst*
2655 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2656
2657 static MonoInst*
2658 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2659 static MonoInst*
2660 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2661
2662 static MonoInst*
2663 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2664                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2665 {
2666 #ifndef DISABLE_REMOTING
2667         gboolean might_be_remote = FALSE;
2668 #endif
2669         gboolean virtual = this != NULL;
2670         gboolean enable_for_aot = TRUE;
2671         int context_used;
2672         MonoCallInst *call;
2673         int rgctx_reg = 0;
2674         gboolean need_unbox_trampoline;
2675
2676         if (!sig)
2677                 sig = mono_method_signature (method);
2678
2679         if (rgctx_arg) {
2680                 rgctx_reg = mono_alloc_preg (cfg);
2681                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2682         }
2683
2684         if (method->string_ctor) {
2685                 /* Create the real signature */
2686                 /* FIXME: Cache these */
2687                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2688                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2689
2690                 sig = ctor_sig;
2691         }
2692
2693         context_used = mini_method_check_context_used (cfg, method);
2694
2695 #ifndef DISABLE_REMOTING
2696         might_be_remote = this && sig->hasthis &&
2697                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2698                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2699
2700         if (might_be_remote && context_used) {
2701                 MonoInst *addr;
2702
2703                 g_assert (cfg->generic_sharing_context);
2704
2705                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2706
2707                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2708         }
2709 #endif
2710
2711         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2712
2713         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2714
2715 #ifndef DISABLE_REMOTING
2716         if (might_be_remote)
2717                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2718         else
2719 #endif
2720                 call->method = method;
2721         call->inst.flags |= MONO_INST_HAS_METHOD;
2722         call->inst.inst_left = this;
2723         call->tail_call = tail;
2724
2725         if (virtual) {
2726                 int vtable_reg, slot_reg, this_reg;
2727                 int offset;
2728
2729                 this_reg = this->dreg;
2730
2731                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2732                         MonoInst *dummy_use;
2733
2734                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2735
2736                         /* Make a call to delegate->invoke_impl */
2737                         call->inst.inst_basereg = this_reg;
2738                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2739                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2740
2741                         /* We must emit a dummy use here because the delegate trampoline will
2742                         replace the 'this' argument with the delegate target making this activation
2743                         no longer a root for the delegate.
2744                         This is an issue for delegates that target collectible code such as dynamic
2745                         methods of GC'able assemblies.
2746
2747                         For a test case look into #667921.
2748
2749                         FIXME: a dummy use is not the best way to do it as the local register allocator
2750                         will put it on a caller save register and spil it around the call. 
2751                         Ideally, we would either put it on a callee save register or only do the store part.  
2752                          */
2753                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2754
2755                         return (MonoInst*)call;
2756                 }
2757
2758                 if ((!cfg->compile_aot || enable_for_aot) && 
2759                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2760                          (MONO_METHOD_IS_FINAL (method) &&
2761                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2762                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2763                         /* 
2764                          * the method is not virtual, we just need to ensure this is not null
2765                          * and then we can call the method directly.
2766                          */
2767 #ifndef DISABLE_REMOTING
2768                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2769                                 /* 
2770                                  * The check above ensures method is not gshared, this is needed since
2771                                  * gshared methods can't have wrappers.
2772                                  */
2773                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2774                         }
2775 #endif
2776
2777                         if (!method->string_ctor)
2778                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2779
2780                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2781                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2782                         /*
2783                          * the method is virtual, but we can statically dispatch since either
2784                          * it's class or the method itself are sealed.
2785                          * But first we need to ensure it's not a null reference.
2786                          */
2787                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2788
2789                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2790                 } else {
2791                         vtable_reg = alloc_preg (cfg);
2792                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2793                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2794                                 slot_reg = -1;
2795 #ifdef MONO_ARCH_HAVE_IMT
2796                                 if (mono_use_imt) {
2797                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2798                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2799                                         slot_reg = vtable_reg;
2800                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2801                                 }
2802 #endif
2803                                 if (slot_reg == -1) {
2804                                         slot_reg = alloc_preg (cfg);
2805                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2806                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2807                                 }
2808                         } else {
2809                                 slot_reg = vtable_reg;
2810                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2811                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2812 #ifdef MONO_ARCH_HAVE_IMT
2813                                 if (imt_arg) {
2814                                         g_assert (mono_method_signature (method)->generic_param_count);
2815                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2816                                 }
2817 #endif
2818                         }
2819
2820                         call->inst.sreg1 = slot_reg;
2821                         call->inst.inst_offset = offset;
2822                         call->virtual = TRUE;
2823                 }
2824         }
2825
2826         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2827
2828         if (rgctx_arg)
2829                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2830
2831         return (MonoInst*)call;
2832 }
2833
2834 MonoInst*
2835 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2836 {
2837         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2838 }
2839
2840 MonoInst*
2841 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2842                                            MonoInst **args)
2843 {
2844         MonoCallInst *call;
2845
2846         g_assert (sig);
2847
2848         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2849         call->fptr = func;
2850
2851         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2852
2853         return (MonoInst*)call;
2854 }
2855
2856 MonoInst*
2857 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2858 {
2859         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2860
2861         g_assert (info);
2862
2863         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2864 }
2865
2866 /*
2867  * mono_emit_abs_call:
2868  *
2869  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2870  */
2871 inline static MonoInst*
2872 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2873                                         MonoMethodSignature *sig, MonoInst **args)
2874 {
2875         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2876         MonoInst *ins;
2877
2878         /* 
2879          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2880          * handle it.
2881          */
2882         if (cfg->abs_patches == NULL)
2883                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2884         g_hash_table_insert (cfg->abs_patches, ji, ji);
2885         ins = mono_emit_native_call (cfg, ji, sig, args);
2886         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2887         return ins;
2888 }
2889  
2890 static MonoInst*
2891 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2892 {
2893         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2894                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2895                         int widen_op = -1;
2896
2897                         /* 
2898                          * Native code might return non register sized integers 
2899                          * without initializing the upper bits.
2900                          */
2901                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2902                         case OP_LOADI1_MEMBASE:
2903                                 widen_op = OP_ICONV_TO_I1;
2904                                 break;
2905                         case OP_LOADU1_MEMBASE:
2906                                 widen_op = OP_ICONV_TO_U1;
2907                                 break;
2908                         case OP_LOADI2_MEMBASE:
2909                                 widen_op = OP_ICONV_TO_I2;
2910                                 break;
2911                         case OP_LOADU2_MEMBASE:
2912                                 widen_op = OP_ICONV_TO_U2;
2913                                 break;
2914                         default:
2915                                 break;
2916                         }
2917
2918                         if (widen_op != -1) {
2919                                 int dreg = alloc_preg (cfg);
2920                                 MonoInst *widen;
2921
2922                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2923                                 widen->type = ins->type;
2924                                 ins = widen;
2925                         }
2926                 }
2927         }
2928
2929         return ins;
2930 }
2931
2932 static MonoMethod*
2933 get_memcpy_method (void)
2934 {
2935         static MonoMethod *memcpy_method = NULL;
2936         if (!memcpy_method) {
2937                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2938                 if (!memcpy_method)
2939                         g_error ("Old corlib found. Install a new one");
2940         }
2941         return memcpy_method;
2942 }
2943
2944 static void
2945 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2946 {
2947         MonoClassField *field;
2948         gpointer iter = NULL;
2949
2950         while ((field = mono_class_get_fields (klass, &iter))) {
2951                 int foffset;
2952
2953                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2954                         continue;
2955                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2956                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2957                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2958                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2959                 } else {
2960                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2961                         if (field_class->has_references)
2962                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2963                 }
2964         }
2965 }
2966
2967 static void
2968 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2969 {
2970         int card_table_shift_bits;
2971         gpointer card_table_mask;
2972         guint8 *card_table;
2973         MonoInst *dummy_use;
2974         int nursery_shift_bits;
2975         size_t nursery_size;
2976         gboolean has_card_table_wb = FALSE;
2977
2978         if (!cfg->gen_write_barriers)
2979                 return;
2980
2981         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2982
2983         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2984
2985 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2986         has_card_table_wb = TRUE;
2987 #endif
2988
2989         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2990                 MonoInst *wbarrier;
2991
2992                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2993                 wbarrier->sreg1 = ptr->dreg;
2994                 wbarrier->sreg2 = value->dreg;
2995                 MONO_ADD_INS (cfg->cbb, wbarrier);
2996         } else if (card_table) {
2997                 int offset_reg = alloc_preg (cfg);
2998                 int card_reg  = alloc_preg (cfg);
2999                 MonoInst *ins;
3000
3001                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3002                 if (card_table_mask)
3003                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3004
3005                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3006                  * IMM's larger than 32bits.
3007                  */
3008                 if (cfg->compile_aot) {
3009                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3010                 } else {
3011                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3012                         ins->inst_p0 = card_table;
3013                         ins->dreg = card_reg;
3014                         MONO_ADD_INS (cfg->cbb, ins);
3015                 }
3016
3017                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3018                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3019         } else {
3020                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3021                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3022         }
3023
3024         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3025 }
3026
3027 static gboolean
3028 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3029 {
3030         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3031         unsigned need_wb = 0;
3032
3033         if (align == 0)
3034                 align = 4;
3035
3036         /*types with references can't have alignment smaller than sizeof(void*) */
3037         if (align < SIZEOF_VOID_P)
3038                 return FALSE;
3039
3040         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3041         if (size > 32 * SIZEOF_VOID_P)
3042                 return FALSE;
3043
3044         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3045
3046         /* We don't unroll more than 5 stores to avoid code bloat. */
3047         if (size > 5 * SIZEOF_VOID_P) {
3048                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3049                 size += (SIZEOF_VOID_P - 1);
3050                 size &= ~(SIZEOF_VOID_P - 1);
3051
3052                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3053                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3054                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3055                 return TRUE;
3056         }
3057
3058         destreg = iargs [0]->dreg;
3059         srcreg = iargs [1]->dreg;
3060         offset = 0;
3061
3062         dest_ptr_reg = alloc_preg (cfg);
3063         tmp_reg = alloc_preg (cfg);
3064
3065         /*tmp = dreg*/
3066         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3067
3068         while (size >= SIZEOF_VOID_P) {
3069                 MonoInst *load_inst;
3070                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3071                 load_inst->dreg = tmp_reg;
3072                 load_inst->inst_basereg = srcreg;
3073                 load_inst->inst_offset = offset;
3074                 MONO_ADD_INS (cfg->cbb, load_inst);
3075
3076                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3077
3078                 if (need_wb & 0x1)
3079                         emit_write_barrier (cfg, iargs [0], load_inst);
3080
3081                 offset += SIZEOF_VOID_P;
3082                 size -= SIZEOF_VOID_P;
3083                 need_wb >>= 1;
3084
3085                 /*tmp += sizeof (void*)*/
3086                 if (size >= SIZEOF_VOID_P) {
3087                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3088                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3089                 }
3090         }
3091
3092         /* Those cannot be references since size < sizeof (void*) */
3093         while (size >= 4) {
3094                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3095                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3096                 offset += 4;
3097                 size -= 4;
3098         }
3099
3100         while (size >= 2) {
3101                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3102                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3103                 offset += 2;
3104                 size -= 2;
3105         }
3106
3107         while (size >= 1) {
3108                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3109                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3110                 offset += 1;
3111                 size -= 1;
3112         }
3113
3114         return TRUE;
3115 }
3116
3117 /*
3118  * Emit code to copy a valuetype of type @klass whose address is stored in
3119  * @src->dreg to memory whose address is stored at @dest->dreg.
3120  */
3121 void
3122 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3123 {
3124         MonoInst *iargs [4];
3125         int context_used, n;
3126         guint32 align = 0;
3127         MonoMethod *memcpy_method;
3128         MonoInst *size_ins = NULL;
3129         MonoInst *memcpy_ins = NULL;
3130
3131         g_assert (klass);
3132         /*
3133          * This check breaks with spilled vars... need to handle it during verification anyway.
3134          * g_assert (klass && klass == src->klass && klass == dest->klass);
3135          */
3136
3137         if (mini_is_gsharedvt_klass (cfg, klass)) {
3138                 g_assert (!native);
3139                 context_used = mini_class_check_context_used (cfg, klass);
3140                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3141                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3142         }
3143
3144         if (native)
3145                 n = mono_class_native_size (klass, &align);
3146         else
3147                 n = mono_class_value_size (klass, &align);
3148
3149         /* if native is true there should be no references in the struct */
3150         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3151                 /* Avoid barriers when storing to the stack */
3152                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3153                           (dest->opcode == OP_LDADDR))) {
3154                         int context_used;
3155
3156                         iargs [0] = dest;
3157                         iargs [1] = src;
3158
3159                         context_used = mini_class_check_context_used (cfg, klass);
3160
3161                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3162                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3163                                 return;
3164                         } else if (context_used) {
3165                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3166                         }  else {
3167                                 if (cfg->compile_aot) {
3168                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3169                                 } else {
3170                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3171                                         mono_class_compute_gc_descriptor (klass);
3172                                 }
3173                         }
3174
3175                         if (size_ins)
3176                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3177                         else
3178                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3179                         return;
3180                 }
3181         }
3182
3183         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3184                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3185                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3186         } else {
3187                 iargs [0] = dest;
3188                 iargs [1] = src;
3189                 if (size_ins)
3190                         iargs [2] = size_ins;
3191                 else
3192                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3193                 
3194                 memcpy_method = get_memcpy_method ();
3195                 if (memcpy_ins)
3196                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3197                 else
3198                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3199         }
3200 }
3201
3202 static MonoMethod*
3203 get_memset_method (void)
3204 {
3205         static MonoMethod *memset_method = NULL;
3206         if (!memset_method) {
3207                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3208                 if (!memset_method)
3209                         g_error ("Old corlib found. Install a new one");
3210         }
3211         return memset_method;
3212 }
3213
3214 void
3215 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3216 {
3217         MonoInst *iargs [3];
3218         int n, context_used;
3219         guint32 align;
3220         MonoMethod *memset_method;
3221         MonoInst *size_ins = NULL;
3222         MonoInst *bzero_ins = NULL;
3223         static MonoMethod *bzero_method;
3224
3225         /* FIXME: Optimize this for the case when dest is an LDADDR */
3226
3227         mono_class_init (klass);
3228         if (mini_is_gsharedvt_klass (cfg, klass)) {
3229                 context_used = mini_class_check_context_used (cfg, klass);
3230                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3231                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3232                 if (!bzero_method)
3233                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3234                 g_assert (bzero_method);
3235                 iargs [0] = dest;
3236                 iargs [1] = size_ins;
3237                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3238                 return;
3239         }
3240
3241         n = mono_class_value_size (klass, &align);
3242
3243         if (n <= sizeof (gpointer) * 5) {
3244                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3245         }
3246         else {
3247                 memset_method = get_memset_method ();
3248                 iargs [0] = dest;
3249                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3250                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3251                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3252         }
3253 }
3254
3255 static MonoInst*
3256 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3257 {
3258         MonoInst *this = NULL;
3259
3260         g_assert (cfg->generic_sharing_context);
3261
3262         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3263                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3264                         !method->klass->valuetype)
3265                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3266
3267         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3268                 MonoInst *mrgctx_loc, *mrgctx_var;
3269
3270                 g_assert (!this);
3271                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3272
3273                 mrgctx_loc = mono_get_vtable_var (cfg);
3274                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3275
3276                 return mrgctx_var;
3277         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3278                 MonoInst *vtable_loc, *vtable_var;
3279
3280                 g_assert (!this);
3281
3282                 vtable_loc = mono_get_vtable_var (cfg);
3283                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3284
3285                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3286                         MonoInst *mrgctx_var = vtable_var;
3287                         int vtable_reg;
3288
3289                         vtable_reg = alloc_preg (cfg);
3290                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3291                         vtable_var->type = STACK_PTR;
3292                 }
3293
3294                 return vtable_var;
3295         } else {
3296                 MonoInst *ins;
3297                 int vtable_reg;
3298         
3299                 vtable_reg = alloc_preg (cfg);
3300                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3301                 return ins;
3302         }
3303 }
3304
3305 static MonoJumpInfoRgctxEntry *
3306 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3307 {
3308         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3309         res->method = method;
3310         res->in_mrgctx = in_mrgctx;
3311         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3312         res->data->type = patch_type;
3313         res->data->data.target = patch_data;
3314         res->info_type = info_type;
3315
3316         return res;
3317 }
3318
3319 static inline MonoInst*
3320 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3321 {
3322         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3323 }
3324
3325 static MonoInst*
3326 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3327                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3328 {
3329         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);
3330         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3331
3332         return emit_rgctx_fetch (cfg, rgctx, entry);
3333 }
3334
3335 static MonoInst*
3336 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3337                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3338 {
3339         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3340         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3341
3342         return emit_rgctx_fetch (cfg, rgctx, entry);
3343 }
3344
3345 static MonoInst*
3346 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3347                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3348 {
3349         MonoJumpInfoGSharedVtCall *call_info;
3350         MonoJumpInfoRgctxEntry *entry;
3351         MonoInst *rgctx;
3352
3353         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3354         call_info->sig = sig;
3355         call_info->method = cmethod;
3356
3357         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3358         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3359
3360         return emit_rgctx_fetch (cfg, rgctx, entry);
3361 }
3362
3363
3364 static MonoInst*
3365 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3366                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3367 {
3368         MonoJumpInfoRgctxEntry *entry;
3369         MonoInst *rgctx;
3370
3371         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3372         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3373
3374         return emit_rgctx_fetch (cfg, rgctx, entry);
3375 }
3376
3377 /*
3378  * emit_get_rgctx_method:
3379  *
3380  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3381  * normal constants, else emit a load from the rgctx.
3382  */
3383 static MonoInst*
3384 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3385                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3386 {
3387         if (!context_used) {
3388                 MonoInst *ins;
3389
3390                 switch (rgctx_type) {
3391                 case MONO_RGCTX_INFO_METHOD:
3392                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3393                         return ins;
3394                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3395                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3396                         return ins;
3397                 default:
3398                         g_assert_not_reached ();
3399                 }
3400         } else {
3401                 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);
3402                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3403
3404                 return emit_rgctx_fetch (cfg, rgctx, entry);
3405         }
3406 }
3407
3408 static MonoInst*
3409 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3410                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3411 {
3412         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);
3413         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3414
3415         return emit_rgctx_fetch (cfg, rgctx, entry);
3416 }
3417
3418 static int
3419 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3420 {
3421         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3422         MonoRuntimeGenericContextInfoTemplate *template;
3423         int i, idx;
3424
3425         g_assert (info);
3426
3427         for (i = 0; i < info->num_entries; ++i) {
3428                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3429
3430                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3431                         return i;
3432         }
3433
3434         if (info->num_entries == info->count_entries) {
3435                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3436                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3437
3438                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3439
3440                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3441                 info->entries = new_entries;
3442                 info->count_entries = new_count_entries;
3443         }
3444
3445         idx = info->num_entries;
3446         template = &info->entries [idx];
3447         template->info_type = rgctx_type;
3448         template->data = data;
3449
3450         info->num_entries ++;
3451
3452         return idx;
3453 }
3454
3455 /*
3456  * emit_get_gsharedvt_info:
3457  *
3458  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3459  */
3460 static MonoInst*
3461 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3462 {
3463         MonoInst *ins;
3464         int idx, dreg;
3465
3466         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3467         /* Load info->entries [idx] */
3468         dreg = alloc_preg (cfg);
3469         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3470
3471         return ins;
3472 }
3473
3474 static MonoInst*
3475 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3476 {
3477         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3478 }
3479
3480 /*
3481  * On return the caller must check @klass for load errors.
3482  */
3483 static void
3484 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3485 {
3486         MonoInst *vtable_arg;
3487         MonoCallInst *call;
3488         int context_used;
3489
3490         context_used = mini_class_check_context_used (cfg, klass);
3491
3492         if (context_used) {
3493                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3494                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3495         } else {
3496                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3497
3498                 if (!vtable)
3499                         return;
3500                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3501         }
3502
3503         if (COMPILE_LLVM (cfg))
3504                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3505         else
3506                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3507 #ifdef MONO_ARCH_VTABLE_REG
3508         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3509         cfg->uses_vtable_reg = TRUE;
3510 #else
3511         NOT_IMPLEMENTED;
3512 #endif
3513 }
3514
3515 static void
3516 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3517 {
3518         MonoInst *ins;
3519
3520         if (cfg->gen_seq_points && cfg->method == method) {
3521                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3522                 if (nonempty_stack)
3523                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3524                 MONO_ADD_INS (cfg->cbb, ins);
3525         }
3526 }
3527
3528 static void
3529 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3530 {
3531         if (mini_get_debug_options ()->better_cast_details) {
3532                 int to_klass_reg = alloc_preg (cfg);
3533                 int vtable_reg = alloc_preg (cfg);
3534                 int klass_reg = alloc_preg (cfg);
3535                 MonoBasicBlock *is_null_bb = NULL;
3536                 MonoInst *tls_get;
3537
3538                 if (null_check) {
3539                         NEW_BBLOCK (cfg, is_null_bb);
3540
3541                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3542                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3543                 }
3544
3545                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3546                 if (!tls_get) {
3547                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3548                         exit (1);
3549                 }
3550
3551                 MONO_ADD_INS (cfg->cbb, tls_get);
3552                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3553                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3554
3555                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3556                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3557                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3558
3559                 if (null_check) {
3560                         MONO_START_BB (cfg, is_null_bb);
3561                         if (out_bblock)
3562                                 *out_bblock = cfg->cbb;
3563                 }
3564         }
3565 }
3566
3567 static void
3568 reset_cast_details (MonoCompile *cfg)
3569 {
3570         /* Reset the variables holding the cast details */
3571         if (mini_get_debug_options ()->better_cast_details) {
3572                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3573
3574                 MONO_ADD_INS (cfg->cbb, tls_get);
3575                 /* It is enough to reset the from field */
3576                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3577         }
3578 }
3579
3580 /*
3581  * On return the caller must check @array_class for load errors
3582  */
3583 static void
3584 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3585 {
3586         int vtable_reg = alloc_preg (cfg);
3587         int context_used;
3588
3589         context_used = mini_class_check_context_used (cfg, array_class);
3590
3591         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3592
3593         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3594
3595         if (cfg->opt & MONO_OPT_SHARED) {
3596                 int class_reg = alloc_preg (cfg);
3597                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3598                 if (cfg->compile_aot) {
3599                         int klass_reg = alloc_preg (cfg);
3600                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3601                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3602                 } else {
3603                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3604                 }
3605         } else if (context_used) {
3606                 MonoInst *vtable_ins;
3607
3608                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3609                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3610         } else {
3611                 if (cfg->compile_aot) {
3612                         int vt_reg;
3613                         MonoVTable *vtable;
3614
3615                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3616                                 return;
3617                         vt_reg = alloc_preg (cfg);
3618                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3619                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3620                 } else {
3621                         MonoVTable *vtable;
3622                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3623                                 return;
3624                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3625                 }
3626         }
3627         
3628         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3629
3630         reset_cast_details (cfg);
3631 }
3632
3633 /**
3634  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3635  * generic code is generated.
3636  */
3637 static MonoInst*
3638 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3639 {
3640         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3641
3642         if (context_used) {
3643                 MonoInst *rgctx, *addr;
3644
3645                 /* FIXME: What if the class is shared?  We might not
3646                    have to get the address of the method from the
3647                    RGCTX. */
3648                 addr = emit_get_rgctx_method (cfg, context_used, method,
3649                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3650
3651                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3652
3653                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3654         } else {
3655                 gboolean pass_vtable, pass_mrgctx;
3656                 MonoInst *rgctx_arg = NULL;
3657
3658                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3659                 g_assert (!pass_mrgctx);
3660
3661                 if (pass_vtable) {
3662                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3663
3664                         g_assert (vtable);
3665                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3666                 }
3667
3668                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3669         }
3670 }
3671
3672 static MonoInst*
3673 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3674 {
3675         MonoInst *add;
3676         int obj_reg;
3677         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3678         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3679         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3680         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3681
3682         obj_reg = sp [0]->dreg;
3683         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3684         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3685
3686         /* FIXME: generics */
3687         g_assert (klass->rank == 0);
3688                         
3689         // Check rank == 0
3690         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3691         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3692
3693         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3694         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3695
3696         if (context_used) {
3697                 MonoInst *element_class;
3698
3699                 /* This assertion is from the unboxcast insn */
3700                 g_assert (klass->rank == 0);
3701
3702                 element_class = emit_get_rgctx_klass (cfg, context_used,
3703                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3704
3705                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3706                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3707         } else {
3708                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3709                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3710                 reset_cast_details (cfg);
3711         }
3712
3713         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3714         MONO_ADD_INS (cfg->cbb, add);
3715         add->type = STACK_MP;
3716         add->klass = klass;
3717
3718         return add;
3719 }
3720
3721 static MonoInst*
3722 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3723 {
3724         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3725         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3726         MonoInst *ins;
3727         int dreg, addr_reg;
3728
3729         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3730
3731         /* obj */
3732         args [0] = obj;
3733
3734         /* klass */
3735         args [1] = klass_inst;
3736
3737         /* CASTCLASS */
3738         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3739
3740         NEW_BBLOCK (cfg, is_ref_bb);
3741         NEW_BBLOCK (cfg, is_nullable_bb);
3742         NEW_BBLOCK (cfg, end_bb);
3743         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3744         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3745         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3746
3747         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3748         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3749
3750         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3751         addr_reg = alloc_dreg (cfg, STACK_MP);
3752
3753         /* Non-ref case */
3754         /* UNBOX */
3755         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3756         MONO_ADD_INS (cfg->cbb, addr);
3757
3758         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3759
3760         /* Ref case */
3761         MONO_START_BB (cfg, is_ref_bb);
3762
3763         /* Save the ref to a temporary */
3764         dreg = alloc_ireg (cfg);
3765         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3766         addr->dreg = addr_reg;
3767         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3768         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3769
3770         /* Nullable case */
3771         MONO_START_BB (cfg, is_nullable_bb);
3772
3773         {
3774                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3775                 MonoInst *unbox_call;
3776                 MonoMethodSignature *unbox_sig;
3777                 MonoInst *var;
3778
3779                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3780
3781                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3782                 unbox_sig->ret = &klass->byval_arg;
3783                 unbox_sig->param_count = 1;
3784                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3785                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3786
3787                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3788                 addr->dreg = addr_reg;
3789         }
3790
3791         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3792
3793         /* End */
3794         MONO_START_BB (cfg, end_bb);
3795
3796         /* LDOBJ */
3797         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3798
3799         *out_cbb = cfg->cbb;
3800
3801         return ins;
3802 }
3803
3804 /*
3805  * Returns NULL and set the cfg exception on error.
3806  */
3807 static MonoInst*
3808 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3809 {
3810         MonoInst *iargs [2];
3811         void *alloc_ftn;
3812
3813         if (context_used) {
3814                 MonoInst *data;
3815                 int rgctx_info;
3816                 MonoInst *iargs [2];
3817
3818                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3819
3820                 if (cfg->opt & MONO_OPT_SHARED)
3821                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3822                 else
3823                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3824                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3825
3826                 if (cfg->opt & MONO_OPT_SHARED) {
3827                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3828                         iargs [1] = data;
3829                         alloc_ftn = mono_object_new;
3830                 } else {
3831                         iargs [0] = data;
3832                         alloc_ftn = mono_object_new_specific;
3833                 }
3834
3835                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3836                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3837
3838                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3839         }
3840
3841         if (cfg->opt & MONO_OPT_SHARED) {
3842                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3843                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3844
3845                 alloc_ftn = mono_object_new;
3846         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3847                 /* This happens often in argument checking code, eg. throw new FooException... */
3848                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3849                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3850                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3851         } else {
3852                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3853                 MonoMethod *managed_alloc = NULL;
3854                 gboolean pass_lw;
3855
3856                 if (!vtable) {
3857                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3858                         cfg->exception_ptr = klass;
3859                         return NULL;
3860                 }
3861
3862 #ifndef MONO_CROSS_COMPILE
3863                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3864 #endif
3865
3866                 if (managed_alloc) {
3867                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3868                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3869                 }
3870                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3871                 if (pass_lw) {
3872                         guint32 lw = vtable->klass->instance_size;
3873                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3874                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3875                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3876                 }
3877                 else {
3878                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3879                 }
3880         }
3881
3882         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3883 }
3884         
3885 /*
3886  * Returns NULL and set the cfg exception on error.
3887  */     
3888 static MonoInst*
3889 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3890 {
3891         MonoInst *alloc, *ins;
3892
3893         *out_cbb = cfg->cbb;
3894
3895         if (mono_class_is_nullable (klass)) {
3896                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3897
3898                 if (context_used) {
3899                         /* FIXME: What if the class is shared?  We might not
3900                            have to get the method address from the RGCTX. */
3901                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3902                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3903                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3904
3905                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3906                 } else {
3907                         gboolean pass_vtable, pass_mrgctx;
3908                         MonoInst *rgctx_arg = NULL;
3909
3910                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3911                         g_assert (!pass_mrgctx);
3912
3913                         if (pass_vtable) {
3914                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3915
3916                                 g_assert (vtable);
3917                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3918                         }
3919
3920                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3921                 }
3922         }
3923
3924         if (mini_is_gsharedvt_klass (cfg, klass)) {
3925                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3926                 MonoInst *res, *is_ref, *src_var, *addr;
3927                 int addr_reg, dreg;
3928
3929                 dreg = alloc_ireg (cfg);
3930
3931                 NEW_BBLOCK (cfg, is_ref_bb);
3932                 NEW_BBLOCK (cfg, is_nullable_bb);
3933                 NEW_BBLOCK (cfg, end_bb);
3934                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3935                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3936                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3937
3938                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3939                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3940
3941                 /* Non-ref case */
3942                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3943                 if (!alloc)
3944                         return NULL;
3945                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3946                 ins->opcode = OP_STOREV_MEMBASE;
3947
3948                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3949                 res->type = STACK_OBJ;
3950                 res->klass = klass;
3951                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3952                 
3953                 /* Ref case */
3954                 MONO_START_BB (cfg, is_ref_bb);
3955                 addr_reg = alloc_ireg (cfg);
3956
3957                 /* val is a vtype, so has to load the value manually */
3958                 src_var = get_vreg_to_inst (cfg, val->dreg);
3959                 if (!src_var)
3960                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3961                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3962                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3963                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3964
3965                 /* Nullable case */
3966                 MONO_START_BB (cfg, is_nullable_bb);
3967
3968                 {
3969                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3970                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3971                         MonoInst *box_call;
3972                         MonoMethodSignature *box_sig;
3973
3974                         /*
3975                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3976                          * construct that method at JIT time, so have to do things by hand.
3977                          */
3978                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3979                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3980                         box_sig->param_count = 1;
3981                         box_sig->params [0] = &klass->byval_arg;
3982                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3983                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3984                         res->type = STACK_OBJ;
3985                         res->klass = klass;
3986                 }
3987
3988                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3989
3990                 MONO_START_BB (cfg, end_bb);
3991
3992                 *out_cbb = cfg->cbb;
3993
3994                 return res;
3995         } else {
3996                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3997                 if (!alloc)
3998                         return NULL;
3999
4000                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4001                 return alloc;
4002         }
4003 }
4004
4005
4006 static gboolean
4007 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4008 {
4009         int i;
4010         MonoGenericContainer *container;
4011         MonoGenericInst *ginst;
4012
4013         if (klass->generic_class) {
4014                 container = klass->generic_class->container_class->generic_container;
4015                 ginst = klass->generic_class->context.class_inst;
4016         } else if (klass->generic_container && context_used) {
4017                 container = klass->generic_container;
4018                 ginst = container->context.class_inst;
4019         } else {
4020                 return FALSE;
4021         }
4022
4023         for (i = 0; i < container->type_argc; ++i) {
4024                 MonoType *type;
4025                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4026                         continue;
4027                 type = ginst->type_argv [i];
4028                 if (mini_type_is_reference (cfg, type))
4029                         return TRUE;
4030         }
4031         return FALSE;
4032 }
4033
4034 // FIXME: This doesn't work yet (class libs tests fail?)
4035 #define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4036
4037 static MonoInst*
4038 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4039 {
4040         MonoMethod *mono_castclass;
4041         MonoInst *res;
4042
4043         mono_castclass = mono_marshal_get_castclass_with_cache ();
4044
4045         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4046         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4047         reset_cast_details (cfg);
4048
4049         return res;
4050 }
4051
4052 /*
4053  * Returns NULL and set the cfg exception on error.
4054  */
4055 static MonoInst*
4056 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4057 {
4058         MonoBasicBlock *is_null_bb;
4059         int obj_reg = src->dreg;
4060         int vtable_reg = alloc_preg (cfg);
4061         MonoInst *klass_inst = NULL;
4062
4063         if (context_used) {
4064                 MonoInst *args [3];
4065
4066                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4067                         MonoInst *cache_ins;
4068
4069                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4070
4071                         /* obj */
4072                         args [0] = src;
4073
4074                         /* klass - it's the second element of the cache entry*/
4075                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4076
4077                         /* cache */
4078                         args [2] = cache_ins;
4079
4080                         return emit_castclass_with_cache (cfg, klass, args, NULL);
4081                 }
4082
4083                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4084         }
4085
4086         NEW_BBLOCK (cfg, is_null_bb);
4087
4088         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4089         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4090
4091         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4092
4093         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4094                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4095                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4096         } else {
4097                 int klass_reg = alloc_preg (cfg);
4098
4099                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4100
4101                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4102                         /* the remoting code is broken, access the class for now */
4103                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4104                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4105                                 if (!vt) {
4106                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4107                                         cfg->exception_ptr = klass;
4108                                         return NULL;
4109                                 }
4110                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4111                         } else {
4112                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4113                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4114                         }
4115                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4116                 } else {
4117                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4118                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4119                 }
4120         }
4121
4122         MONO_START_BB (cfg, is_null_bb);
4123
4124         reset_cast_details (cfg);
4125
4126         return src;
4127 }
4128
4129 /*
4130  * Returns NULL and set the cfg exception on error.
4131  */
4132 static MonoInst*
4133 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4134 {
4135         MonoInst *ins;
4136         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4137         int obj_reg = src->dreg;
4138         int vtable_reg = alloc_preg (cfg);
4139         int res_reg = alloc_ireg_ref (cfg);
4140         MonoInst *klass_inst = NULL;
4141
4142         if (context_used) {
4143                 MonoInst *args [3];
4144
4145                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4146                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4147                         MonoInst *cache_ins;
4148
4149                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4150
4151                         /* obj */
4152                         args [0] = src;
4153
4154                         /* klass - it's the second element of the cache entry*/
4155                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4156
4157                         /* cache */
4158                         args [2] = cache_ins;
4159
4160                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4161                 }
4162
4163                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4164         }
4165
4166         NEW_BBLOCK (cfg, is_null_bb);
4167         NEW_BBLOCK (cfg, false_bb);
4168         NEW_BBLOCK (cfg, end_bb);
4169
4170         /* Do the assignment at the beginning, so the other assignment can be if converted */
4171         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4172         ins->type = STACK_OBJ;
4173         ins->klass = klass;
4174
4175         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4176         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4177
4178         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4179
4180         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4181                 g_assert (!context_used);
4182                 /* the is_null_bb target simply copies the input register to the output */
4183                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4184         } else {
4185                 int klass_reg = alloc_preg (cfg);
4186
4187                 if (klass->rank) {
4188                         int rank_reg = alloc_preg (cfg);
4189                         int eclass_reg = alloc_preg (cfg);
4190
4191                         g_assert (!context_used);
4192                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4193                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4194                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4195                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4196                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4197                         if (klass->cast_class == mono_defaults.object_class) {
4198                                 int parent_reg = alloc_preg (cfg);
4199                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4200                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4201                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4202                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4203                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4204                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4205                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4206                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4207                         } else if (klass->cast_class == mono_defaults.enum_class) {
4208                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4209                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4210                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4211                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4212                         } else {
4213                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4214                                         /* Check that the object is a vector too */
4215                                         int bounds_reg = alloc_preg (cfg);
4216                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4217                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4218                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4219                                 }
4220
4221                                 /* the is_null_bb target simply copies the input register to the output */
4222                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4223                         }
4224                 } else if (mono_class_is_nullable (klass)) {
4225                         g_assert (!context_used);
4226                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4227                         /* the is_null_bb target simply copies the input register to the output */
4228                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4229                 } else {
4230                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4231                                 g_assert (!context_used);
4232                                 /* the remoting code is broken, access the class for now */
4233                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4234                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4235                                         if (!vt) {
4236                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4237                                                 cfg->exception_ptr = klass;
4238                                                 return NULL;
4239                                         }
4240                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4241                                 } else {
4242                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4243                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4244                                 }
4245                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4246                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4247                         } else {
4248                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4249                                 /* the is_null_bb target simply copies the input register to the output */
4250                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4251                         }
4252                 }
4253         }
4254
4255         MONO_START_BB (cfg, false_bb);
4256
4257         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4258         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4259
4260         MONO_START_BB (cfg, is_null_bb);
4261
4262         MONO_START_BB (cfg, end_bb);
4263
4264         return ins;
4265 }
4266
4267 static MonoInst*
4268 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4269 {
4270         /* This opcode takes as input an object reference and a class, and returns:
4271         0) if the object is an instance of the class,
4272         1) if the object is not instance of the class,
4273         2) if the object is a proxy whose type cannot be determined */
4274
4275         MonoInst *ins;
4276 #ifndef DISABLE_REMOTING
4277         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4278 #else
4279         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4280 #endif
4281         int obj_reg = src->dreg;
4282         int dreg = alloc_ireg (cfg);
4283         int tmp_reg;
4284 #ifndef DISABLE_REMOTING
4285         int klass_reg = alloc_preg (cfg);
4286 #endif
4287
4288         NEW_BBLOCK (cfg, true_bb);
4289         NEW_BBLOCK (cfg, false_bb);
4290         NEW_BBLOCK (cfg, end_bb);
4291 #ifndef DISABLE_REMOTING
4292         NEW_BBLOCK (cfg, false2_bb);
4293         NEW_BBLOCK (cfg, no_proxy_bb);
4294 #endif
4295
4296         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4297         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4298
4299         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4300 #ifndef DISABLE_REMOTING
4301                 NEW_BBLOCK (cfg, interface_fail_bb);
4302 #endif
4303
4304                 tmp_reg = alloc_preg (cfg);
4305                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4306 #ifndef DISABLE_REMOTING
4307                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4308                 MONO_START_BB (cfg, interface_fail_bb);
4309                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4310                 
4311                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4312
4313                 tmp_reg = alloc_preg (cfg);
4314                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4315                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4316                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4317 #else
4318                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4319 #endif
4320         } else {
4321 #ifndef DISABLE_REMOTING
4322                 tmp_reg = alloc_preg (cfg);
4323                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4324                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4325
4326                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4327                 tmp_reg = alloc_preg (cfg);
4328                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4329                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4330
4331                 tmp_reg = alloc_preg (cfg);             
4332                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4333                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4334                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4335                 
4336                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4337                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4338
4339                 MONO_START_BB (cfg, no_proxy_bb);
4340
4341                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4342 #else
4343                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4344 #endif
4345         }
4346
4347         MONO_START_BB (cfg, false_bb);
4348
4349         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4350         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4351
4352 #ifndef DISABLE_REMOTING
4353         MONO_START_BB (cfg, false2_bb);
4354
4355         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4356         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4357 #endif
4358
4359         MONO_START_BB (cfg, true_bb);
4360
4361         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4362
4363         MONO_START_BB (cfg, end_bb);
4364
4365         /* FIXME: */
4366         MONO_INST_NEW (cfg, ins, OP_ICONST);
4367         ins->dreg = dreg;
4368         ins->type = STACK_I4;
4369
4370         return ins;
4371 }
4372
4373 static MonoInst*
4374 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4375 {
4376         /* This opcode takes as input an object reference and a class, and returns:
4377         0) if the object is an instance of the class,
4378         1) if the object is a proxy whose type cannot be determined
4379         an InvalidCastException exception is thrown otherwhise*/
4380         
4381         MonoInst *ins;
4382 #ifndef DISABLE_REMOTING
4383         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4384 #else
4385         MonoBasicBlock *ok_result_bb;
4386 #endif
4387         int obj_reg = src->dreg;
4388         int dreg = alloc_ireg (cfg);
4389         int tmp_reg = alloc_preg (cfg);
4390
4391 #ifndef DISABLE_REMOTING
4392         int klass_reg = alloc_preg (cfg);
4393         NEW_BBLOCK (cfg, end_bb);
4394 #endif
4395
4396         NEW_BBLOCK (cfg, ok_result_bb);
4397
4398         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4399         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4400
4401         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4402
4403         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4404 #ifndef DISABLE_REMOTING
4405                 NEW_BBLOCK (cfg, interface_fail_bb);
4406         
4407                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4408                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4409                 MONO_START_BB (cfg, interface_fail_bb);
4410                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4411
4412                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4413
4414                 tmp_reg = alloc_preg (cfg);             
4415                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4416                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4417                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4418                 
4419                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4420                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4421 #else
4422                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4423                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4424                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4425 #endif
4426         } else {
4427 #ifndef DISABLE_REMOTING
4428                 NEW_BBLOCK (cfg, no_proxy_bb);
4429
4430                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4431                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4432                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4433
4434                 tmp_reg = alloc_preg (cfg);
4435                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4436                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4437
4438                 tmp_reg = alloc_preg (cfg);
4439                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4440                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4441                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4442
4443                 NEW_BBLOCK (cfg, fail_1_bb);
4444                 
4445                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4446
4447                 MONO_START_BB (cfg, fail_1_bb);
4448
4449                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4450                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4451
4452                 MONO_START_BB (cfg, no_proxy_bb);
4453
4454                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4455 #else
4456                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4457 #endif
4458         }
4459
4460         MONO_START_BB (cfg, ok_result_bb);
4461
4462         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4463
4464 #ifndef DISABLE_REMOTING
4465         MONO_START_BB (cfg, end_bb);
4466 #endif
4467
4468         /* FIXME: */
4469         MONO_INST_NEW (cfg, ins, OP_ICONST);
4470         ins->dreg = dreg;
4471         ins->type = STACK_I4;
4472
4473         return ins;
4474 }
4475
4476 /*
4477  * Returns NULL and set the cfg exception on error.
4478  */
4479 static G_GNUC_UNUSED MonoInst*
4480 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4481 {
4482         MonoInst *ptr;
4483         int dreg;
4484         gpointer *trampoline;
4485         MonoInst *obj, *method_ins, *tramp_ins;
4486         MonoDomain *domain;
4487         guint8 **code_slot;
4488
4489         obj = handle_alloc (cfg, klass, FALSE, 0);
4490         if (!obj)
4491                 return NULL;
4492
4493         /* Inline the contents of mono_delegate_ctor */
4494
4495         /* Set target field */
4496         /* Optimize away setting of NULL target */
4497         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4498                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4499                 if (cfg->gen_write_barriers) {
4500                         dreg = alloc_preg (cfg);
4501                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4502                         emit_write_barrier (cfg, ptr, target);
4503                 }
4504         }
4505
4506         /* Set method field */
4507         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4508         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4509         if (cfg->gen_write_barriers) {
4510                 dreg = alloc_preg (cfg);
4511                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4512                 emit_write_barrier (cfg, ptr, method_ins);
4513         }
4514         /* 
4515          * To avoid looking up the compiled code belonging to the target method
4516          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4517          * store it, and we fill it after the method has been compiled.
4518          */
4519         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4520                 MonoInst *code_slot_ins;
4521
4522                 if (context_used) {
4523                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4524                 } else {
4525                         domain = mono_domain_get ();
4526                         mono_domain_lock (domain);
4527                         if (!domain_jit_info (domain)->method_code_hash)
4528                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4529                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4530                         if (!code_slot) {
4531                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4532                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4533                         }
4534                         mono_domain_unlock (domain);
4535
4536                         if (cfg->compile_aot)
4537                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4538                         else
4539                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4540                 }
4541                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4542         }
4543
4544         /* Set invoke_impl field */
4545         if (cfg->compile_aot) {
4546                 MonoClassMethodPair *del_tramp;
4547
4548                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoClassMethodPair));
4549                 del_tramp->klass = klass;
4550                 del_tramp->method = context_used ? NULL : method;
4551                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4552         } else {
4553                 trampoline = mono_create_delegate_trampoline_with_method (cfg->domain, klass, context_used ? NULL : method);
4554                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4555         }
4556         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4557
4558         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4559
4560         return obj;
4561 }
4562
4563 static MonoInst*
4564 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4565 {
4566         MonoJitICallInfo *info;
4567
4568         /* Need to register the icall so it gets an icall wrapper */
4569         info = mono_get_array_new_va_icall (rank);
4570
4571         cfg->flags |= MONO_CFG_HAS_VARARGS;
4572
4573         /* mono_array_new_va () needs a vararg calling convention */
4574         cfg->disable_llvm = TRUE;
4575
4576         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4577         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4578 }
4579
4580 static void
4581 mono_emit_load_got_addr (MonoCompile *cfg)
4582 {
4583         MonoInst *getaddr, *dummy_use;
4584
4585         if (!cfg->got_var || cfg->got_var_allocated)
4586                 return;
4587
4588         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4589         getaddr->cil_code = cfg->header->code;
4590         getaddr->dreg = cfg->got_var->dreg;
4591
4592         /* Add it to the start of the first bblock */
4593         if (cfg->bb_entry->code) {
4594                 getaddr->next = cfg->bb_entry->code;
4595                 cfg->bb_entry->code = getaddr;
4596         }
4597         else
4598                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4599
4600         cfg->got_var_allocated = TRUE;
4601
4602         /* 
4603          * Add a dummy use to keep the got_var alive, since real uses might
4604          * only be generated by the back ends.
4605          * Add it to end_bblock, so the variable's lifetime covers the whole
4606          * method.
4607          * It would be better to make the usage of the got var explicit in all
4608          * cases when the backend needs it (i.e. calls, throw etc.), so this
4609          * wouldn't be needed.
4610          */
4611         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4612         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4613 }
4614
4615 static int inline_limit;
4616 static gboolean inline_limit_inited;
4617
4618 static gboolean
4619 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4620 {
4621         MonoMethodHeaderSummary header;
4622         MonoVTable *vtable;
4623 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4624         MonoMethodSignature *sig = mono_method_signature (method);
4625         int i;
4626 #endif
4627
4628         if (cfg->generic_sharing_context)
4629                 return FALSE;
4630
4631         if (cfg->inline_depth > 10)
4632                 return FALSE;
4633
4634 #ifdef MONO_ARCH_HAVE_LMF_OPS
4635         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4636                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4637             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4638                 return TRUE;
4639 #endif
4640
4641
4642         if (!mono_method_get_header_summary (method, &header))
4643                 return FALSE;
4644
4645         /*runtime, icall and pinvoke are checked by summary call*/
4646         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4647             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4648             (mono_class_is_marshalbyref (method->klass)) ||
4649             header.has_clauses)
4650                 return FALSE;
4651
4652         /* also consider num_locals? */
4653         /* Do the size check early to avoid creating vtables */
4654         if (!inline_limit_inited) {
4655                 if (g_getenv ("MONO_INLINELIMIT"))
4656                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4657                 else
4658                         inline_limit = INLINE_LENGTH_LIMIT;
4659                 inline_limit_inited = TRUE;
4660         }
4661         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4662                 return FALSE;
4663
4664         /*
4665          * if we can initialize the class of the method right away, we do,
4666          * otherwise we don't allow inlining if the class needs initialization,
4667          * since it would mean inserting a call to mono_runtime_class_init()
4668          * inside the inlined code
4669          */
4670         if (!(cfg->opt & MONO_OPT_SHARED)) {
4671                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4672                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4673                         vtable = mono_class_vtable (cfg->domain, method->klass);
4674                         if (!vtable)
4675                                 return FALSE;
4676                         if (!cfg->compile_aot)
4677                                 mono_runtime_class_init (vtable);
4678                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4679                         if (cfg->run_cctors && method->klass->has_cctor) {
4680                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4681                                 if (!method->klass->runtime_info)
4682                                         /* No vtable created yet */
4683                                         return FALSE;
4684                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4685                                 if (!vtable)
4686                                         return FALSE;
4687                                 /* This makes so that inline cannot trigger */
4688                                 /* .cctors: too many apps depend on them */
4689                                 /* running with a specific order... */
4690                                 if (! vtable->initialized)
4691                                         return FALSE;
4692                                 mono_runtime_class_init (vtable);
4693                         }
4694                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4695                         if (!method->klass->runtime_info)
4696                                 /* No vtable created yet */
4697                                 return FALSE;
4698                         vtable = mono_class_vtable (cfg->domain, method->klass);
4699                         if (!vtable)
4700                                 return FALSE;
4701                         if (!vtable->initialized)
4702                                 return FALSE;
4703                 }
4704         } else {
4705                 /* 
4706                  * If we're compiling for shared code
4707                  * the cctor will need to be run at aot method load time, for example,
4708                  * or at the end of the compilation of the inlining method.
4709                  */
4710                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4711                         return FALSE;
4712         }
4713
4714         /*
4715          * CAS - do not inline methods with declarative security
4716          * Note: this has to be before any possible return TRUE;
4717          */
4718         if (mono_security_method_has_declsec (method))
4719                 return FALSE;
4720
4721 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4722         if (mono_arch_is_soft_float ()) {
4723                 /* FIXME: */
4724                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4725                         return FALSE;
4726                 for (i = 0; i < sig->param_count; ++i)
4727                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4728                                 return FALSE;
4729         }
4730 #endif
4731
4732         return TRUE;
4733 }
4734
4735 static gboolean
4736 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4737 {
4738         if (!cfg->compile_aot) {
4739                 g_assert (vtable);
4740                 if (vtable->initialized)
4741                         return FALSE;
4742         }
4743
4744         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4745                 if (cfg->method == method)
4746                         return FALSE;
4747         }
4748
4749         if (!mono_class_needs_cctor_run (klass, method))
4750                 return FALSE;
4751
4752         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4753                 /* The initialization is already done before the method is called */
4754                 return FALSE;
4755
4756         return TRUE;
4757 }
4758
4759 static MonoInst*
4760 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4761 {
4762         MonoInst *ins;
4763         guint32 size;
4764         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4765         int context_used;
4766
4767         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4768                 size = -1;
4769         } else {
4770                 mono_class_init (klass);
4771                 size = mono_class_array_element_size (klass);
4772         }
4773
4774         mult_reg = alloc_preg (cfg);
4775         array_reg = arr->dreg;
4776         index_reg = index->dreg;
4777
4778 #if SIZEOF_REGISTER == 8
4779         /* The array reg is 64 bits but the index reg is only 32 */
4780         if (COMPILE_LLVM (cfg)) {
4781                 /* Not needed */
4782                 index2_reg = index_reg;
4783         } else {
4784                 index2_reg = alloc_preg (cfg);
4785                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4786         }
4787 #else
4788         if (index->type == STACK_I8) {
4789                 index2_reg = alloc_preg (cfg);
4790                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4791         } else {
4792                 index2_reg = index_reg;
4793         }
4794 #endif
4795
4796         if (bcheck)
4797                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4798
4799 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4800         if (size == 1 || size == 2 || size == 4 || size == 8) {
4801                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4802
4803                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4804                 ins->klass = mono_class_get_element_class (klass);
4805                 ins->type = STACK_MP;
4806
4807                 return ins;
4808         }
4809 #endif          
4810
4811         add_reg = alloc_ireg_mp (cfg);
4812
4813         if (size == -1) {
4814                 MonoInst *rgctx_ins;
4815
4816                 /* gsharedvt */
4817                 g_assert (cfg->generic_sharing_context);
4818                 context_used = mini_class_check_context_used (cfg, klass);
4819                 g_assert (context_used);
4820                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4821                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4822         } else {
4823                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4824         }
4825         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4826         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4827         ins->klass = mono_class_get_element_class (klass);
4828         ins->type = STACK_MP;
4829         MONO_ADD_INS (cfg->cbb, ins);
4830
4831         return ins;
4832 }
4833
4834 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4835 static MonoInst*
4836 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4837 {
4838         int bounds_reg = alloc_preg (cfg);
4839         int add_reg = alloc_ireg_mp (cfg);
4840         int mult_reg = alloc_preg (cfg);
4841         int mult2_reg = alloc_preg (cfg);
4842         int low1_reg = alloc_preg (cfg);
4843         int low2_reg = alloc_preg (cfg);
4844         int high1_reg = alloc_preg (cfg);
4845         int high2_reg = alloc_preg (cfg);
4846         int realidx1_reg = alloc_preg (cfg);
4847         int realidx2_reg = alloc_preg (cfg);
4848         int sum_reg = alloc_preg (cfg);
4849         int index1, index2, tmpreg;
4850         MonoInst *ins;
4851         guint32 size;
4852
4853         mono_class_init (klass);
4854         size = mono_class_array_element_size (klass);
4855
4856         index1 = index_ins1->dreg;
4857         index2 = index_ins2->dreg;
4858
4859 #if SIZEOF_REGISTER == 8
4860         /* The array reg is 64 bits but the index reg is only 32 */
4861         if (COMPILE_LLVM (cfg)) {
4862                 /* Not needed */
4863         } else {
4864                 tmpreg = alloc_preg (cfg);
4865                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4866                 index1 = tmpreg;
4867                 tmpreg = alloc_preg (cfg);
4868                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4869                 index2 = tmpreg;
4870         }
4871 #else
4872         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4873         tmpreg = -1;
4874 #endif
4875
4876         /* range checking */
4877         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4878                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4879
4880         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4881                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4882         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4883         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4884                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4885         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4886         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4887
4888         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4889                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4890         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4891         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4892                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4893         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4894         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4895
4896         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4897         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4898         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4899         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4900         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4901
4902         ins->type = STACK_MP;
4903         ins->klass = klass;
4904         MONO_ADD_INS (cfg->cbb, ins);
4905
4906         return ins;
4907 }
4908 #endif
4909
4910 static MonoInst*
4911 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4912 {
4913         int rank;
4914         MonoInst *addr;
4915         MonoMethod *addr_method;
4916         int element_size;
4917
4918         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4919
4920         if (rank == 1)
4921                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4922
4923 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4924         /* emit_ldelema_2 depends on OP_LMUL */
4925         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4926                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4927         }
4928 #endif
4929
4930         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4931         addr_method = mono_marshal_get_array_address (rank, element_size);
4932         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4933
4934         return addr;
4935 }
4936
4937 static MonoBreakPolicy
4938 always_insert_breakpoint (MonoMethod *method)
4939 {
4940         return MONO_BREAK_POLICY_ALWAYS;
4941 }
4942
4943 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4944
4945 /**
4946  * mono_set_break_policy:
4947  * policy_callback: the new callback function
4948  *
4949  * Allow embedders to decide wherther to actually obey breakpoint instructions
4950  * (both break IL instructions and Debugger.Break () method calls), for example
4951  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4952  * untrusted or semi-trusted code.
4953  *
4954  * @policy_callback will be called every time a break point instruction needs to
4955  * be inserted with the method argument being the method that calls Debugger.Break()
4956  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4957  * if it wants the breakpoint to not be effective in the given method.
4958  * #MONO_BREAK_POLICY_ALWAYS is the default.
4959  */
4960 void
4961 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4962 {
4963         if (policy_callback)
4964                 break_policy_func = policy_callback;
4965         else
4966                 break_policy_func = always_insert_breakpoint;
4967 }
4968
4969 static gboolean
4970 should_insert_brekpoint (MonoMethod *method) {
4971         switch (break_policy_func (method)) {
4972         case MONO_BREAK_POLICY_ALWAYS:
4973                 return TRUE;
4974         case MONO_BREAK_POLICY_NEVER:
4975                 return FALSE;
4976         case MONO_BREAK_POLICY_ON_DBG:
4977                 g_warning ("mdb no longer supported");
4978                 return FALSE;
4979         default:
4980                 g_warning ("Incorrect value returned from break policy callback");
4981                 return FALSE;
4982         }
4983 }
4984
4985 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4986 static MonoInst*
4987 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4988 {
4989         MonoInst *addr, *store, *load;
4990         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4991
4992         /* the bounds check is already done by the callers */
4993         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4994         if (is_set) {
4995                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4996                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4997                 if (mini_type_is_reference (cfg, fsig->params [2]))
4998                         emit_write_barrier (cfg, addr, load);
4999         } else {
5000                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5001                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5002         }
5003         return store;
5004 }
5005
5006
5007 static gboolean
5008 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5009 {
5010         return mini_type_is_reference (cfg, &klass->byval_arg);
5011 }
5012
5013 static MonoInst*
5014 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5015 {
5016         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5017                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5018                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5019                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5020                 MonoInst *iargs [3];
5021
5022                 if (!helper->slot)
5023                         mono_class_setup_vtable (obj_array);
5024                 g_assert (helper->slot);
5025
5026                 if (sp [0]->type != STACK_OBJ)
5027                         return NULL;
5028                 if (sp [2]->type != STACK_OBJ)
5029                         return NULL;
5030
5031                 iargs [2] = sp [2];
5032                 iargs [1] = sp [1];
5033                 iargs [0] = sp [0];
5034
5035                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5036         } else {
5037                 MonoInst *ins;
5038
5039                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5040                         MonoInst *addr;
5041
5042                         // FIXME-VT: OP_ICONST optimization
5043                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5044                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5045                         ins->opcode = OP_STOREV_MEMBASE;
5046                 } else if (sp [1]->opcode == OP_ICONST) {
5047                         int array_reg = sp [0]->dreg;
5048                         int index_reg = sp [1]->dreg;
5049                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
5050
5051                         if (safety_checks)
5052                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5053                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5054                 } else {
5055                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5056                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5057                         if (generic_class_is_reference_type (cfg, klass))
5058                                 emit_write_barrier (cfg, addr, sp [2]);
5059                 }
5060                 return ins;
5061         }
5062 }
5063
5064 static MonoInst*
5065 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5066 {
5067         MonoClass *eklass;
5068         
5069         if (is_set)
5070                 eklass = mono_class_from_mono_type (fsig->params [2]);
5071         else
5072                 eklass = mono_class_from_mono_type (fsig->ret);
5073
5074         if (is_set) {
5075                 return emit_array_store (cfg, eklass, args, FALSE);
5076         } else {
5077                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5078                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5079                 return ins;
5080         }
5081 }
5082
5083 static gboolean
5084 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5085 {
5086         uint32_t align;
5087
5088         //Only allow for valuetypes
5089         if (!param_klass->valuetype || !return_klass->valuetype)
5090                 return FALSE;
5091
5092         //That are blitable
5093         if (param_klass->has_references || return_klass->has_references)
5094                 return FALSE;
5095
5096         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5097         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5098                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5099                 return FALSE;
5100
5101         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5102                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5103                 return FALSE;
5104
5105         //And have the same size
5106         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5107                 return FALSE;
5108         return TRUE;
5109 }
5110
5111 static MonoInst*
5112 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5113 {
5114         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5115         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5116
5117         //Valuetypes that are semantically equivalent
5118         if (is_unsafe_mov_compatible (param_klass, return_klass))
5119                 return args [0];
5120
5121         //Arrays of valuetypes that are semantically equivalent
5122         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5123                 return args [0];
5124
5125         return NULL;
5126 }
5127
5128 static MonoInst*
5129 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5130 {
5131 #ifdef MONO_ARCH_SIMD_INTRINSICS
5132         MonoInst *ins = NULL;
5133
5134         if (cfg->opt & MONO_OPT_SIMD) {
5135                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5136                 if (ins)
5137                         return ins;
5138         }
5139 #endif
5140
5141         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5142 }
5143
5144 static MonoInst*
5145 emit_memory_barrier (MonoCompile *cfg, int kind)
5146 {
5147         MonoInst *ins = NULL;
5148         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5149         MONO_ADD_INS (cfg->cbb, ins);
5150         ins->backend.memory_barrier_kind = kind;
5151
5152         return ins;
5153 }
5154
5155 static MonoInst*
5156 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5157 {
5158         MonoInst *ins = NULL;
5159         int opcode = 0;
5160
5161         /* The LLVM backend supports these intrinsics */
5162         if (cmethod->klass == mono_defaults.math_class) {
5163                 if (strcmp (cmethod->name, "Sin") == 0) {
5164                         opcode = OP_SIN;
5165                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5166                         opcode = OP_COS;
5167                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5168                         opcode = OP_SQRT;
5169                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5170                         opcode = OP_ABS;
5171                 }
5172
5173                 if (opcode) {
5174                         MONO_INST_NEW (cfg, ins, opcode);
5175                         ins->type = STACK_R8;
5176                         ins->dreg = mono_alloc_freg (cfg);
5177                         ins->sreg1 = args [0]->dreg;
5178                         MONO_ADD_INS (cfg->cbb, ins);
5179                 }
5180
5181                 opcode = 0;
5182                 if (cfg->opt & MONO_OPT_CMOV) {
5183                         if (strcmp (cmethod->name, "Min") == 0) {
5184                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5185                                         opcode = OP_IMIN;
5186                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5187                                         opcode = OP_IMIN_UN;
5188                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5189                                         opcode = OP_LMIN;
5190                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5191                                         opcode = OP_LMIN_UN;
5192                         } else if (strcmp (cmethod->name, "Max") == 0) {
5193                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5194                                         opcode = OP_IMAX;
5195                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5196                                         opcode = OP_IMAX_UN;
5197                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5198                                         opcode = OP_LMAX;
5199                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5200                                         opcode = OP_LMAX_UN;
5201                         }
5202                 }
5203
5204                 if (opcode) {
5205                         MONO_INST_NEW (cfg, ins, opcode);
5206                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5207                         ins->dreg = mono_alloc_ireg (cfg);
5208                         ins->sreg1 = args [0]->dreg;
5209                         ins->sreg2 = args [1]->dreg;
5210                         MONO_ADD_INS (cfg->cbb, ins);
5211                 }
5212         }
5213
5214         return ins;
5215 }
5216
5217 static MonoInst*
5218 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5219 {
5220         if (cmethod->klass == mono_defaults.array_class) {
5221                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5222                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5223                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5224                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5225                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5226                         return emit_array_unsafe_mov (cfg, fsig, args);
5227         }
5228
5229         return NULL;
5230 }
5231
5232 static MonoInst*
5233 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5234 {
5235         MonoInst *ins = NULL;
5236         
5237         static MonoClass *runtime_helpers_class = NULL;
5238         if (! runtime_helpers_class)
5239                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5240                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5241
5242         if (cmethod->klass == mono_defaults.string_class) {
5243                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5244                         int dreg = alloc_ireg (cfg);
5245                         int index_reg = alloc_preg (cfg);
5246                         int mult_reg = alloc_preg (cfg);
5247                         int add_reg = alloc_preg (cfg);
5248
5249 #if SIZEOF_REGISTER == 8
5250                         /* The array reg is 64 bits but the index reg is only 32 */
5251                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5252 #else
5253                         index_reg = args [1]->dreg;
5254 #endif  
5255                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5256
5257 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5258                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5259                         add_reg = ins->dreg;
5260                         /* Avoid a warning */
5261                         mult_reg = 0;
5262                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5263                                                                    add_reg, 0);
5264 #else
5265                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5266                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5267                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5268                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5269 #endif
5270                         type_from_op (ins, NULL, NULL);
5271                         return ins;
5272                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5273                         int dreg = alloc_ireg (cfg);
5274                         /* Decompose later to allow more optimizations */
5275                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5276                         ins->type = STACK_I4;
5277                         ins->flags |= MONO_INST_FAULT;
5278                         cfg->cbb->has_array_access = TRUE;
5279                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5280
5281                         return ins;
5282                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5283                         int mult_reg = alloc_preg (cfg);
5284                         int add_reg = alloc_preg (cfg);
5285
5286                         /* The corlib functions check for oob already. */
5287                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5288                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5289                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5290                         return cfg->cbb->last_ins;
5291                 } else 
5292                         return NULL;
5293         } else if (cmethod->klass == mono_defaults.object_class) {
5294
5295                 if (strcmp (cmethod->name, "GetType") == 0) {
5296                         int dreg = alloc_ireg_ref (cfg);
5297                         int vt_reg = alloc_preg (cfg);
5298                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5299                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5300                         type_from_op (ins, NULL, NULL);
5301
5302                         return ins;
5303 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5304                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5305                         int dreg = alloc_ireg (cfg);
5306                         int t1 = alloc_ireg (cfg);
5307         
5308                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5309                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5310                         ins->type = STACK_I4;
5311
5312                         return ins;
5313 #endif
5314                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5315                         MONO_INST_NEW (cfg, ins, OP_NOP);
5316                         MONO_ADD_INS (cfg->cbb, ins);
5317                         return ins;
5318                 } else
5319                         return NULL;
5320         } else if (cmethod->klass == mono_defaults.array_class) {
5321                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5322                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5323
5324 #ifndef MONO_BIG_ARRAYS
5325                 /*
5326                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5327                  * Array methods.
5328                  */
5329                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5330                         int dreg = alloc_ireg (cfg);
5331                         int bounds_reg = alloc_ireg_mp (cfg);
5332                         MonoBasicBlock *end_bb, *szarray_bb;
5333                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5334
5335                         NEW_BBLOCK (cfg, end_bb);
5336                         NEW_BBLOCK (cfg, szarray_bb);
5337
5338                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5339                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5340                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5341                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5342                         /* Non-szarray case */
5343                         if (get_length)
5344                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5345                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5346                         else
5347                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5348                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5349                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5350                         MONO_START_BB (cfg, szarray_bb);
5351                         /* Szarray case */
5352                         if (get_length)
5353                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5354                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5355                         else
5356                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5357                         MONO_START_BB (cfg, end_bb);
5358
5359                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5360                         ins->type = STACK_I4;
5361                         
5362                         return ins;
5363                 }
5364 #endif
5365
5366                 if (cmethod->name [0] != 'g')
5367                         return NULL;
5368
5369                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5370                         int dreg = alloc_ireg (cfg);
5371                         int vtable_reg = alloc_preg (cfg);
5372                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5373                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5374                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5375                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5376                         type_from_op (ins, NULL, NULL);
5377
5378                         return ins;
5379                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5380                         int dreg = alloc_ireg (cfg);
5381
5382                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5383                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5384                         type_from_op (ins, NULL, NULL);
5385
5386                         return ins;
5387                 } else
5388                         return NULL;
5389         } else if (cmethod->klass == runtime_helpers_class) {
5390
5391                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5392                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5393                         return ins;
5394                 } else
5395                         return NULL;
5396         } else if (cmethod->klass == mono_defaults.thread_class) {
5397                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5398                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5399                         MONO_ADD_INS (cfg->cbb, ins);
5400                         return ins;
5401                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5402                         return emit_memory_barrier (cfg, FullBarrier);
5403                 }
5404         } else if (cmethod->klass == mono_defaults.monitor_class) {
5405
5406                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5407 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5408                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5409                         MonoMethod *fast_method = NULL;
5410
5411                         /* Avoid infinite recursion */
5412                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5413                                 return NULL;
5414                                 
5415                         fast_method = mono_monitor_get_fast_path (cmethod);
5416                         if (!fast_method)
5417                                 return NULL;
5418
5419                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5420                 }
5421 #endif
5422
5423 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5424                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5425                         MonoCallInst *call;
5426
5427                         if (COMPILE_LLVM (cfg)) {
5428                                 /* 
5429                                  * Pass the argument normally, the LLVM backend will handle the
5430                                  * calling convention problems.
5431                                  */
5432                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5433                         } else {
5434                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5435                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5436                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5437                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5438                         }
5439
5440                         return (MonoInst*)call;
5441                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5442                         MonoCallInst *call;
5443
5444                         if (COMPILE_LLVM (cfg)) {
5445                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5446                         } else {
5447                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5448                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5449                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5450                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5451                         }
5452
5453                         return (MonoInst*)call;
5454                 }
5455 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5456                 {
5457                 MonoMethod *fast_method = NULL;
5458
5459                 /* Avoid infinite recursion */
5460                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5461                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5462                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5463                         return NULL;
5464
5465                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5466                                 strcmp (cmethod->name, "Exit") == 0)
5467                         fast_method = mono_monitor_get_fast_path (cmethod);
5468                 if (!fast_method)
5469                         return NULL;
5470
5471                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5472                 }
5473 #endif
5474         } else if (cmethod->klass->image == mono_defaults.corlib &&
5475                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5476                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5477                 ins = NULL;
5478
5479 #if SIZEOF_REGISTER == 8
5480                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5481                         /* 64 bit reads are already atomic */
5482                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5483                         ins->dreg = mono_alloc_preg (cfg);
5484                         ins->inst_basereg = args [0]->dreg;
5485                         ins->inst_offset = 0;
5486                         MONO_ADD_INS (cfg->cbb, ins);
5487                 }
5488 #endif
5489
5490 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5491                 if (strcmp (cmethod->name, "Increment") == 0) {
5492                         MonoInst *ins_iconst;
5493                         guint32 opcode = 0;
5494
5495                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5496                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5497                                 cfg->has_atomic_add_new_i4 = TRUE;
5498                         }
5499 #if SIZEOF_REGISTER == 8
5500                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5501                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5502 #endif
5503                         if (opcode) {
5504                                 if (!mono_arch_opcode_supported (opcode))
5505                                         return NULL;
5506                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5507                                 ins_iconst->inst_c0 = 1;
5508                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5509                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5510
5511                                 MONO_INST_NEW (cfg, ins, opcode);
5512                                 ins->dreg = mono_alloc_ireg (cfg);
5513                                 ins->inst_basereg = args [0]->dreg;
5514                                 ins->inst_offset = 0;
5515                                 ins->sreg2 = ins_iconst->dreg;
5516                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5517                                 MONO_ADD_INS (cfg->cbb, ins);
5518                         }
5519                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5520                         MonoInst *ins_iconst;
5521                         guint32 opcode = 0;
5522
5523                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5524                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5525                                 cfg->has_atomic_add_new_i4 = TRUE;
5526                         }
5527 #if SIZEOF_REGISTER == 8
5528                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5529                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5530 #endif
5531                         if (opcode) {
5532                                 if (!mono_arch_opcode_supported (opcode))
5533                                         return NULL;
5534                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5535                                 ins_iconst->inst_c0 = -1;
5536                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5537                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5538
5539                                 MONO_INST_NEW (cfg, ins, opcode);
5540                                 ins->dreg = mono_alloc_ireg (cfg);
5541                                 ins->inst_basereg = args [0]->dreg;
5542                                 ins->inst_offset = 0;
5543                                 ins->sreg2 = ins_iconst->dreg;
5544                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5545                                 MONO_ADD_INS (cfg->cbb, ins);
5546                         }
5547                 } else if (strcmp (cmethod->name, "Add") == 0) {
5548                         guint32 opcode = 0;
5549
5550                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5551                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5552                                 cfg->has_atomic_add_new_i4 = TRUE;
5553                         }
5554 #if SIZEOF_REGISTER == 8
5555                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5556                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5557 #endif
5558                         if (opcode) {
5559                                 if (!mono_arch_opcode_supported (opcode))
5560                                         return NULL;
5561                                 MONO_INST_NEW (cfg, ins, opcode);
5562                                 ins->dreg = mono_alloc_ireg (cfg);
5563                                 ins->inst_basereg = args [0]->dreg;
5564                                 ins->inst_offset = 0;
5565                                 ins->sreg2 = args [1]->dreg;
5566                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5567                                 MONO_ADD_INS (cfg->cbb, ins);
5568                         }
5569                 }
5570 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5571
5572 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5573                 if (strcmp (cmethod->name, "Exchange") == 0) {
5574                         guint32 opcode;
5575                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5576
5577                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5578                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5579                                 cfg->has_atomic_exchange_i4 = TRUE;
5580                         }
5581 #if SIZEOF_REGISTER == 8
5582                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5583                                         (fsig->params [0]->type == MONO_TYPE_I))
5584                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5585 #else
5586                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5587                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5588                                 cfg->has_atomic_exchange_i4 = TRUE;
5589                         }
5590 #endif
5591                         else
5592                                 return NULL;
5593
5594                         if (!mono_arch_opcode_supported (opcode))
5595                                 return NULL;
5596
5597                         MONO_INST_NEW (cfg, ins, opcode);
5598                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5599                         ins->inst_basereg = args [0]->dreg;
5600                         ins->inst_offset = 0;
5601                         ins->sreg2 = args [1]->dreg;
5602                         MONO_ADD_INS (cfg->cbb, ins);
5603
5604                         switch (fsig->params [0]->type) {
5605                         case MONO_TYPE_I4:
5606                                 ins->type = STACK_I4;
5607                                 break;
5608                         case MONO_TYPE_I8:
5609                         case MONO_TYPE_I:
5610                                 ins->type = STACK_I8;
5611                                 break;
5612                         case MONO_TYPE_OBJECT:
5613                                 ins->type = STACK_OBJ;
5614                                 break;
5615                         default:
5616                                 g_assert_not_reached ();
5617                         }
5618
5619                         if (cfg->gen_write_barriers && is_ref)
5620                                 emit_write_barrier (cfg, args [0], args [1]);
5621                 }
5622 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5623  
5624 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5625                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5626                         int size = 0;
5627                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5628                         if (fsig->params [1]->type == MONO_TYPE_I4)
5629                                 size = 4;
5630                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5631                                 size = sizeof (gpointer);
5632                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5633                                 size = 8;
5634                         if (size == 4) {
5635                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5636                                         return NULL;
5637                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5638                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5639                                 ins->sreg1 = args [0]->dreg;
5640                                 ins->sreg2 = args [1]->dreg;
5641                                 ins->sreg3 = args [2]->dreg;
5642                                 ins->type = STACK_I4;
5643                                 MONO_ADD_INS (cfg->cbb, ins);
5644                                 cfg->has_atomic_cas_i4 = TRUE;
5645                         } else if (size == 8) {
5646                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5647                                         return NULL;
5648                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5649                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5650                                 ins->sreg1 = args [0]->dreg;
5651                                 ins->sreg2 = args [1]->dreg;
5652                                 ins->sreg3 = args [2]->dreg;
5653                                 ins->type = STACK_I8;
5654                                 MONO_ADD_INS (cfg->cbb, ins);
5655                         } else {
5656                                 /* g_assert_not_reached (); */
5657                         }
5658                         if (cfg->gen_write_barriers && is_ref)
5659                                 emit_write_barrier (cfg, args [0], args [1]);
5660                 }
5661 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5662
5663                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5664                         ins = emit_memory_barrier (cfg, FullBarrier);
5665
5666                 if (ins)
5667                         return ins;
5668         } else if (cmethod->klass->image == mono_defaults.corlib) {
5669                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5670                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5671                         if (should_insert_brekpoint (cfg->method)) {
5672                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5673                         } else {
5674                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5675                                 MONO_ADD_INS (cfg->cbb, ins);
5676                         }
5677                         return ins;
5678                 }
5679                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5680                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5681 #ifdef TARGET_WIN32
5682                         EMIT_NEW_ICONST (cfg, ins, 1);
5683 #else
5684                         EMIT_NEW_ICONST (cfg, ins, 0);
5685 #endif
5686                         return ins;
5687                 }
5688         } else if (cmethod->klass == mono_defaults.math_class) {
5689                 /* 
5690                  * There is general branches code for Min/Max, but it does not work for 
5691                  * all inputs:
5692                  * http://everything2.com/?node_id=1051618
5693                  */
5694         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") || !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) && !strcmp (cmethod->klass->name, "Selector") && !strcmp (cmethod->name, "GetHandle") && cfg->compile_aot && (args [0]->opcode == OP_GOT_ENTRY || args[0]->opcode == OP_AOTCONST)) {
5695 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5696                 MonoInst *pi;
5697                 MonoJumpInfoToken *ji;
5698                 MonoString *s;
5699
5700                 cfg->disable_llvm = TRUE;
5701
5702                 if (args [0]->opcode == OP_GOT_ENTRY) {
5703                         pi = args [0]->inst_p1;
5704                         g_assert (pi->opcode == OP_PATCH_INFO);
5705                         g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
5706                         ji = pi->inst_p0;
5707                 } else {
5708                         g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
5709                         ji = args [0]->inst_p0;
5710                 }
5711
5712                 NULLIFY_INS (args [0]);
5713
5714                 // FIXME: Ugly
5715                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5716                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5717                 ins->dreg = mono_alloc_ireg (cfg);
5718                 // FIXME: Leaks
5719                 ins->inst_p0 = mono_string_to_utf8 (s);
5720                 MONO_ADD_INS (cfg->cbb, ins);
5721                 return ins;
5722 #endif
5723         }
5724
5725 #ifdef MONO_ARCH_SIMD_INTRINSICS
5726         if (cfg->opt & MONO_OPT_SIMD) {
5727                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5728                 if (ins)
5729                         return ins;
5730         }
5731 #endif
5732
5733         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5734         if (ins)
5735                 return ins;
5736
5737         if (COMPILE_LLVM (cfg)) {
5738                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5739                 if (ins)
5740                         return ins;
5741         }
5742
5743         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5744 }
5745
5746 /*
5747  * This entry point could be used later for arbitrary method
5748  * redirection.
5749  */
5750 inline static MonoInst*
5751 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5752                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5753 {
5754         if (method->klass == mono_defaults.string_class) {
5755                 /* managed string allocation support */
5756                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5757                         MonoInst *iargs [2];
5758                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5759                         MonoMethod *managed_alloc = NULL;
5760
5761                         g_assert (vtable); /*Should not fail since it System.String*/
5762 #ifndef MONO_CROSS_COMPILE
5763                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5764 #endif
5765                         if (!managed_alloc)
5766                                 return NULL;
5767                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5768                         iargs [1] = args [0];
5769                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5770                 }
5771         }
5772         return NULL;
5773 }
5774
5775 static void
5776 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5777 {
5778         MonoInst *store, *temp;
5779         int i;
5780
5781         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5782                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5783
5784                 /*
5785                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5786                  * would be different than the MonoInst's used to represent arguments, and
5787                  * the ldelema implementation can't deal with that.
5788                  * Solution: When ldelema is used on an inline argument, create a var for 
5789                  * it, emit ldelema on that var, and emit the saving code below in
5790                  * inline_method () if needed.
5791                  */
5792                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5793                 cfg->args [i] = temp;
5794                 /* This uses cfg->args [i] which is set by the preceeding line */
5795                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5796                 store->cil_code = sp [0]->cil_code;
5797                 sp++;
5798         }
5799 }
5800
5801 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5802 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5803
5804 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5805 static gboolean
5806 check_inline_called_method_name_limit (MonoMethod *called_method)
5807 {
5808         int strncmp_result;
5809         static const char *limit = NULL;
5810         
5811         if (limit == NULL) {
5812                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5813
5814                 if (limit_string != NULL)
5815                         limit = limit_string;
5816                 else
5817                         limit = "";
5818         }
5819
5820         if (limit [0] != '\0') {
5821                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5822
5823                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5824                 g_free (called_method_name);
5825         
5826                 //return (strncmp_result <= 0);
5827                 return (strncmp_result == 0);
5828         } else {
5829                 return TRUE;
5830         }
5831 }
5832 #endif
5833
5834 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5835 static gboolean
5836 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5837 {
5838         int strncmp_result;
5839         static const char *limit = NULL;
5840         
5841         if (limit == NULL) {
5842                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5843                 if (limit_string != NULL) {
5844                         limit = limit_string;
5845                 } else {
5846                         limit = "";
5847                 }
5848         }
5849
5850         if (limit [0] != '\0') {
5851                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5852
5853                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5854                 g_free (caller_method_name);
5855         
5856                 //return (strncmp_result <= 0);
5857                 return (strncmp_result == 0);
5858         } else {
5859                 return TRUE;
5860         }
5861 }
5862 #endif
5863
5864 static void
5865 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5866 {
5867         static double r8_0 = 0.0;
5868         MonoInst *ins;
5869         int t;
5870
5871         rtype = mini_replace_type (rtype);
5872         t = rtype->type;
5873
5874         if (rtype->byref) {
5875                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5876         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5877                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5878         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5879                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5880         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5881                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5882                 ins->type = STACK_R8;
5883                 ins->inst_p0 = (void*)&r8_0;
5884                 ins->dreg = dreg;
5885                 MONO_ADD_INS (cfg->cbb, ins);
5886         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5887                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5888                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5889         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5890                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5891         } else {
5892                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5893         }
5894 }
5895
5896 static void
5897 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5898 {
5899         int t;
5900
5901         rtype = mini_replace_type (rtype);
5902         t = rtype->type;
5903
5904         if (rtype->byref) {
5905                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
5906         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5907                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
5908         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5909                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
5910         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5911                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
5912         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5913                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5914                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5915         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5916                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5917         } else {
5918                 emit_init_rvar (cfg, dreg, rtype);
5919         }
5920 }
5921
5922 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
5923 static void
5924 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
5925 {
5926         MonoInst *var = cfg->locals [local];
5927         if (COMPILE_SOFT_FLOAT (cfg)) {
5928                 MonoInst *store;
5929                 int reg = alloc_dreg (cfg, var->type);
5930                 emit_init_rvar (cfg, reg, type);
5931                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5932         } else {
5933                 if (init)
5934                         emit_init_rvar (cfg, var->dreg, type);
5935                 else
5936                         emit_dummy_init_rvar (cfg, var->dreg, type);
5937         }
5938 }
5939
5940 static int
5941 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5942                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5943 {
5944         MonoInst *ins, *rvar = NULL;
5945         MonoMethodHeader *cheader;
5946         MonoBasicBlock *ebblock, *sbblock;
5947         int i, costs;
5948         MonoMethod *prev_inlined_method;
5949         MonoInst **prev_locals, **prev_args;
5950         MonoType **prev_arg_types;
5951         guint prev_real_offset;
5952         GHashTable *prev_cbb_hash;
5953         MonoBasicBlock **prev_cil_offset_to_bb;
5954         MonoBasicBlock *prev_cbb;
5955         unsigned char* prev_cil_start;
5956         guint32 prev_cil_offset_to_bb_len;
5957         MonoMethod *prev_current_method;
5958         MonoGenericContext *prev_generic_context;
5959         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5960
5961         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5962
5963 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5964         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5965                 return 0;
5966 #endif
5967 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5968         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5969                 return 0;
5970 #endif
5971
5972         if (cfg->verbose_level > 2)
5973                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5974
5975         if (!cmethod->inline_info) {
5976                 cfg->stat_inlineable_methods++;
5977                 cmethod->inline_info = 1;
5978         }
5979
5980         /* allocate local variables */
5981         cheader = mono_method_get_header (cmethod);
5982
5983         if (cheader == NULL || mono_loader_get_last_error ()) {
5984                 MonoLoaderError *error = mono_loader_get_last_error ();
5985
5986                 if (cheader)
5987                         mono_metadata_free_mh (cheader);
5988                 if (inline_always && error)
5989                         mono_cfg_set_exception (cfg, error->exception_type);
5990
5991                 mono_loader_clear_error ();
5992                 return 0;
5993         }
5994
5995         /*Must verify before creating locals as it can cause the JIT to assert.*/
5996         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5997                 mono_metadata_free_mh (cheader);
5998                 return 0;
5999         }
6000
6001         /* allocate space to store the return value */
6002         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6003                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6004         }
6005
6006         prev_locals = cfg->locals;
6007         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6008         for (i = 0; i < cheader->num_locals; ++i)
6009                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6010
6011         /* allocate start and end blocks */
6012         /* This is needed so if the inline is aborted, we can clean up */
6013         NEW_BBLOCK (cfg, sbblock);
6014         sbblock->real_offset = real_offset;
6015
6016         NEW_BBLOCK (cfg, ebblock);
6017         ebblock->block_num = cfg->num_bblocks++;
6018         ebblock->real_offset = real_offset;
6019
6020         prev_args = cfg->args;
6021         prev_arg_types = cfg->arg_types;
6022         prev_inlined_method = cfg->inlined_method;
6023         cfg->inlined_method = cmethod;
6024         cfg->ret_var_set = FALSE;
6025         cfg->inline_depth ++;
6026         prev_real_offset = cfg->real_offset;
6027         prev_cbb_hash = cfg->cbb_hash;
6028         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6029         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6030         prev_cil_start = cfg->cil_start;
6031         prev_cbb = cfg->cbb;
6032         prev_current_method = cfg->current_method;
6033         prev_generic_context = cfg->generic_context;
6034         prev_ret_var_set = cfg->ret_var_set;
6035
6036         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6037                 virtual = TRUE;
6038
6039         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
6040
6041         ret_var_set = cfg->ret_var_set;
6042
6043         cfg->inlined_method = prev_inlined_method;
6044         cfg->real_offset = prev_real_offset;
6045         cfg->cbb_hash = prev_cbb_hash;
6046         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6047         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6048         cfg->cil_start = prev_cil_start;
6049         cfg->locals = prev_locals;
6050         cfg->args = prev_args;
6051         cfg->arg_types = prev_arg_types;
6052         cfg->current_method = prev_current_method;
6053         cfg->generic_context = prev_generic_context;
6054         cfg->ret_var_set = prev_ret_var_set;
6055         cfg->inline_depth --;
6056
6057         if ((costs >= 0 && costs < 60) || inline_always) {
6058                 if (cfg->verbose_level > 2)
6059                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6060                 
6061                 cfg->stat_inlined_methods++;
6062
6063                 /* always add some code to avoid block split failures */
6064                 MONO_INST_NEW (cfg, ins, OP_NOP);
6065                 MONO_ADD_INS (prev_cbb, ins);
6066
6067                 prev_cbb->next_bb = sbblock;
6068                 link_bblock (cfg, prev_cbb, sbblock);
6069
6070                 /* 
6071                  * Get rid of the begin and end bblocks if possible to aid local
6072                  * optimizations.
6073                  */
6074                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6075
6076                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6077                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6078
6079                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6080                         MonoBasicBlock *prev = ebblock->in_bb [0];
6081                         mono_merge_basic_blocks (cfg, prev, ebblock);
6082                         cfg->cbb = prev;
6083                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6084                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6085                                 cfg->cbb = prev_cbb;
6086                         }
6087                 } else {
6088                         /* 
6089                          * Its possible that the rvar is set in some prev bblock, but not in others.
6090                          * (#1835).
6091                          */
6092                         if (rvar) {
6093                                 MonoBasicBlock *bb;
6094
6095                                 for (i = 0; i < ebblock->in_count; ++i) {
6096                                         bb = ebblock->in_bb [i];
6097
6098                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6099                                                 cfg->cbb = bb;
6100
6101                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6102                                         }
6103                                 }
6104                         }
6105
6106                         cfg->cbb = ebblock;
6107                 }
6108
6109                 if (rvar) {
6110                         /*
6111                          * If the inlined method contains only a throw, then the ret var is not 
6112                          * set, so set it to a dummy value.
6113                          */
6114                         if (!ret_var_set)
6115                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6116
6117                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6118                         *sp++ = ins;
6119                 }
6120                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6121                 return costs + 1;
6122         } else {
6123                 if (cfg->verbose_level > 2)
6124                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6125                 cfg->exception_type = MONO_EXCEPTION_NONE;
6126                 mono_loader_clear_error ();
6127
6128                 /* This gets rid of the newly added bblocks */
6129                 cfg->cbb = prev_cbb;
6130         }
6131         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6132         return 0;
6133 }
6134
6135 /*
6136  * Some of these comments may well be out-of-date.
6137  * Design decisions: we do a single pass over the IL code (and we do bblock 
6138  * splitting/merging in the few cases when it's required: a back jump to an IL
6139  * address that was not already seen as bblock starting point).
6140  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6141  * Complex operations are decomposed in simpler ones right away. We need to let the 
6142  * arch-specific code peek and poke inside this process somehow (except when the 
6143  * optimizations can take advantage of the full semantic info of coarse opcodes).
6144  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6145  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6146  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6147  * opcode with value bigger than OP_LAST.
6148  * At this point the IR can be handed over to an interpreter, a dumb code generator
6149  * or to the optimizing code generator that will translate it to SSA form.
6150  *
6151  * Profiling directed optimizations.
6152  * We may compile by default with few or no optimizations and instrument the code
6153  * or the user may indicate what methods to optimize the most either in a config file
6154  * or through repeated runs where the compiler applies offline the optimizations to 
6155  * each method and then decides if it was worth it.
6156  */
6157
6158 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6159 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6160 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6161 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6162 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6163 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6164 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6165 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
6166
6167 /* offset from br.s -> br like opcodes */
6168 #define BIG_BRANCH_OFFSET 13
6169
6170 static gboolean
6171 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6172 {
6173         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6174
6175         return b == NULL || b == bb;
6176 }
6177
6178 static int
6179 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6180 {
6181         unsigned char *ip = start;
6182         unsigned char *target;
6183         int i;
6184         guint cli_addr;
6185         MonoBasicBlock *bblock;
6186         const MonoOpcode *opcode;
6187
6188         while (ip < end) {
6189                 cli_addr = ip - start;
6190                 i = mono_opcode_value ((const guint8 **)&ip, end);
6191                 if (i < 0)
6192                         UNVERIFIED;
6193                 opcode = &mono_opcodes [i];
6194                 switch (opcode->argument) {
6195                 case MonoInlineNone:
6196                         ip++; 
6197                         break;
6198                 case MonoInlineString:
6199                 case MonoInlineType:
6200                 case MonoInlineField:
6201                 case MonoInlineMethod:
6202                 case MonoInlineTok:
6203                 case MonoInlineSig:
6204                 case MonoShortInlineR:
6205                 case MonoInlineI:
6206                         ip += 5;
6207                         break;
6208                 case MonoInlineVar:
6209                         ip += 3;
6210                         break;
6211                 case MonoShortInlineVar:
6212                 case MonoShortInlineI:
6213                         ip += 2;
6214                         break;
6215                 case MonoShortInlineBrTarget:
6216                         target = start + cli_addr + 2 + (signed char)ip [1];
6217                         GET_BBLOCK (cfg, bblock, target);
6218                         ip += 2;
6219                         if (ip < end)
6220                                 GET_BBLOCK (cfg, bblock, ip);
6221                         break;
6222                 case MonoInlineBrTarget:
6223                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6224                         GET_BBLOCK (cfg, bblock, target);
6225                         ip += 5;
6226                         if (ip < end)
6227                                 GET_BBLOCK (cfg, bblock, ip);
6228                         break;
6229                 case MonoInlineSwitch: {
6230                         guint32 n = read32 (ip + 1);
6231                         guint32 j;
6232                         ip += 5;
6233                         cli_addr += 5 + 4 * n;
6234                         target = start + cli_addr;
6235                         GET_BBLOCK (cfg, bblock, target);
6236                         
6237                         for (j = 0; j < n; ++j) {
6238                                 target = start + cli_addr + (gint32)read32 (ip);
6239                                 GET_BBLOCK (cfg, bblock, target);
6240                                 ip += 4;
6241                         }
6242                         break;
6243                 }
6244                 case MonoInlineR:
6245                 case MonoInlineI8:
6246                         ip += 9;
6247                         break;
6248                 default:
6249                         g_assert_not_reached ();
6250                 }
6251
6252                 if (i == CEE_THROW) {
6253                         unsigned char *bb_start = ip - 1;
6254                         
6255                         /* Find the start of the bblock containing the throw */
6256                         bblock = NULL;
6257                         while ((bb_start >= start) && !bblock) {
6258                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6259                                 bb_start --;
6260                         }
6261                         if (bblock)
6262                                 bblock->out_of_line = 1;
6263                 }
6264         }
6265         return 0;
6266 unverified:
6267 exception_exit:
6268         *pos = ip;
6269         return 1;
6270 }
6271
6272 static inline MonoMethod *
6273 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6274 {
6275         MonoMethod *method;
6276
6277         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6278                 method = mono_method_get_wrapper_data (m, token);
6279                 if (context)
6280                         method = mono_class_inflate_generic_method (method, context);
6281         } else {
6282                 method = mono_get_method_full (m->klass->image, token, klass, context);
6283         }
6284
6285         return method;
6286 }
6287
6288 static inline MonoMethod *
6289 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6290 {
6291         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6292
6293         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6294                 return NULL;
6295
6296         return method;
6297 }
6298
6299 static inline MonoClass*
6300 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6301 {
6302         MonoClass *klass;
6303
6304         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6305                 klass = mono_method_get_wrapper_data (method, token);
6306                 if (context)
6307                         klass = mono_class_inflate_generic_class (klass, context);
6308         } else {
6309                 klass = mono_class_get_full (method->klass->image, token, context);
6310         }
6311         if (klass)
6312                 mono_class_init (klass);
6313         return klass;
6314 }
6315
6316 static inline MonoMethodSignature*
6317 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6318 {
6319         MonoMethodSignature *fsig;
6320
6321         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6322                 MonoError error;
6323
6324                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6325                 if (context) {
6326                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6327                         // FIXME:
6328                         g_assert (mono_error_ok (&error));
6329                 }
6330         } else {
6331                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6332         }
6333         return fsig;
6334 }
6335
6336 /*
6337  * Returns TRUE if the JIT should abort inlining because "callee"
6338  * is influenced by security attributes.
6339  */
6340 static
6341 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6342 {
6343         guint32 result;
6344         
6345         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6346                 return TRUE;
6347         }
6348         
6349         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6350         if (result == MONO_JIT_SECURITY_OK)
6351                 return FALSE;
6352
6353         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6354                 /* Generate code to throw a SecurityException before the actual call/link */
6355                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6356                 MonoInst *args [2];
6357
6358                 NEW_ICONST (cfg, args [0], 4);
6359                 NEW_METHODCONST (cfg, args [1], caller);
6360                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6361         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6362                  /* don't hide previous results */
6363                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6364                 cfg->exception_data = result;
6365                 return TRUE;
6366         }
6367         
6368         return FALSE;
6369 }
6370
6371 static MonoMethod*
6372 throw_exception (void)
6373 {
6374         static MonoMethod *method = NULL;
6375
6376         if (!method) {
6377                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6378                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6379         }
6380         g_assert (method);
6381         return method;
6382 }
6383
6384 static void
6385 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6386 {
6387         MonoMethod *thrower = throw_exception ();
6388         MonoInst *args [1];
6389
6390         EMIT_NEW_PCONST (cfg, args [0], ex);
6391         mono_emit_method_call (cfg, thrower, args, NULL);
6392 }
6393
6394 /*
6395  * Return the original method is a wrapper is specified. We can only access 
6396  * the custom attributes from the original method.
6397  */
6398 static MonoMethod*
6399 get_original_method (MonoMethod *method)
6400 {
6401         if (method->wrapper_type == MONO_WRAPPER_NONE)
6402                 return method;
6403
6404         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6405         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6406                 return NULL;
6407
6408         /* in other cases we need to find the original method */
6409         return mono_marshal_method_from_wrapper (method);
6410 }
6411
6412 static void
6413 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6414                                           MonoBasicBlock *bblock, unsigned char *ip)
6415 {
6416         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6417         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6418         if (ex)
6419                 emit_throw_exception (cfg, ex);
6420 }
6421
6422 static void
6423 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6424                                          MonoBasicBlock *bblock, unsigned char *ip)
6425 {
6426         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6427         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6428         if (ex)
6429                 emit_throw_exception (cfg, ex);
6430 }
6431
6432 /*
6433  * Check that the IL instructions at ip are the array initialization
6434  * sequence and return the pointer to the data and the size.
6435  */
6436 static const char*
6437 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6438 {
6439         /*
6440          * newarr[System.Int32]
6441          * dup
6442          * ldtoken field valuetype ...
6443          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6444          */
6445         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6446                 guint32 token = read32 (ip + 7);
6447                 guint32 field_token = read32 (ip + 2);
6448                 guint32 field_index = field_token & 0xffffff;
6449                 guint32 rva;
6450                 const char *data_ptr;
6451                 int size = 0;
6452                 MonoMethod *cmethod;
6453                 MonoClass *dummy_class;
6454                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6455                 int dummy_align;
6456
6457                 if (!field)
6458                         return NULL;
6459
6460                 *out_field_token = field_token;
6461
6462                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6463                 if (!cmethod)
6464                         return NULL;
6465                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6466                         return NULL;
6467                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6468                 case MONO_TYPE_BOOLEAN:
6469                 case MONO_TYPE_I1:
6470                 case MONO_TYPE_U1:
6471                         size = 1; break;
6472                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6473 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6474                 case MONO_TYPE_CHAR:
6475                 case MONO_TYPE_I2:
6476                 case MONO_TYPE_U2:
6477                         size = 2; break;
6478                 case MONO_TYPE_I4:
6479                 case MONO_TYPE_U4:
6480                 case MONO_TYPE_R4:
6481                         size = 4; break;
6482                 case MONO_TYPE_R8:
6483                 case MONO_TYPE_I8:
6484                 case MONO_TYPE_U8:
6485                         size = 8; break;
6486 #endif
6487                 default:
6488                         return NULL;
6489                 }
6490                 size *= len;
6491                 if (size > mono_type_size (field->type, &dummy_align))
6492                     return NULL;
6493                 *out_size = size;
6494                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6495                 if (!method->klass->image->dynamic) {
6496                         field_index = read32 (ip + 2) & 0xffffff;
6497                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6498                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6499                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6500                         /* for aot code we do the lookup on load */
6501                         if (aot && data_ptr)
6502                                 return GUINT_TO_POINTER (rva);
6503                 } else {
6504                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6505                         g_assert (!aot);
6506                         data_ptr = mono_field_get_data (field);
6507                 }
6508                 return data_ptr;
6509         }
6510         return NULL;
6511 }
6512
6513 static void
6514 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6515 {
6516         char *method_fname = mono_method_full_name (method, TRUE);
6517         char *method_code;
6518         MonoMethodHeader *header = mono_method_get_header (method);
6519
6520         if (header->code_size == 0)
6521                 method_code = g_strdup ("method body is empty.");
6522         else
6523                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6524         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6525         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6526         g_free (method_fname);
6527         g_free (method_code);
6528         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6529 }
6530
6531 static void
6532 set_exception_object (MonoCompile *cfg, MonoException *exception)
6533 {
6534         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6535         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6536         cfg->exception_ptr = exception;
6537 }
6538
6539 static void
6540 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6541 {
6542         MonoInst *ins;
6543         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6544         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6545                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6546                 /* Optimize reg-reg moves away */
6547                 /* 
6548                  * Can't optimize other opcodes, since sp[0] might point to
6549                  * the last ins of a decomposed opcode.
6550                  */
6551                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6552         } else {
6553                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6554         }
6555 }
6556
6557 /*
6558  * ldloca inhibits many optimizations so try to get rid of it in common
6559  * cases.
6560  */
6561 static inline unsigned char *
6562 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6563 {
6564         int local, token;
6565         MonoClass *klass;
6566         MonoType *type;
6567
6568         if (size == 1) {
6569                 local = ip [1];
6570                 ip += 2;
6571         } else {
6572                 local = read16 (ip + 2);
6573                 ip += 4;
6574         }
6575         
6576         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6577                 /* From the INITOBJ case */
6578                 token = read32 (ip + 2);
6579                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6580                 CHECK_TYPELOAD (klass);
6581                 type = mini_replace_type (&klass->byval_arg);
6582                 emit_init_local (cfg, local, type, TRUE);
6583                 return ip + 6;
6584         }
6585 load_error:
6586         return NULL;
6587 }
6588
6589 static gboolean
6590 is_exception_class (MonoClass *class)
6591 {
6592         while (class) {
6593                 if (class == mono_defaults.exception_class)
6594                         return TRUE;
6595                 class = class->parent;
6596         }
6597         return FALSE;
6598 }
6599
6600 /*
6601  * is_jit_optimizer_disabled:
6602  *
6603  *   Determine whenever M's assembly has a DebuggableAttribute with the
6604  * IsJITOptimizerDisabled flag set.
6605  */
6606 static gboolean
6607 is_jit_optimizer_disabled (MonoMethod *m)
6608 {
6609         MonoAssembly *ass = m->klass->image->assembly;
6610         MonoCustomAttrInfo* attrs;
6611         static MonoClass *klass;
6612         int i;
6613         gboolean val = FALSE;
6614
6615         g_assert (ass);
6616         if (ass->jit_optimizer_disabled_inited)
6617                 return ass->jit_optimizer_disabled;
6618
6619         if (!klass)
6620                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6621         if (!klass) {
6622                 /* Linked away */
6623                 ass->jit_optimizer_disabled = FALSE;
6624                 mono_memory_barrier ();
6625                 ass->jit_optimizer_disabled_inited = TRUE;
6626                 return FALSE;
6627         }
6628
6629         attrs = mono_custom_attrs_from_assembly (ass);
6630         if (attrs) {
6631                 for (i = 0; i < attrs->num_attrs; ++i) {
6632                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6633                         const gchar *p;
6634                         int len;
6635                         MonoMethodSignature *sig;
6636
6637                         if (!attr->ctor || attr->ctor->klass != klass)
6638                                 continue;
6639                         /* Decode the attribute. See reflection.c */
6640                         len = attr->data_size;
6641                         p = (const char*)attr->data;
6642                         g_assert (read16 (p) == 0x0001);
6643                         p += 2;
6644
6645                         // FIXME: Support named parameters
6646                         sig = mono_method_signature (attr->ctor);
6647                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6648                                 continue;
6649                         /* Two boolean arguments */
6650                         p ++;
6651                         val = *p;
6652                 }
6653                 mono_custom_attrs_free (attrs);
6654         }
6655
6656         ass->jit_optimizer_disabled = val;
6657         mono_memory_barrier ();
6658         ass->jit_optimizer_disabled_inited = TRUE;
6659
6660         return val;
6661 }
6662
6663 static gboolean
6664 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6665 {
6666         gboolean supported_tail_call;
6667         int i;
6668
6669 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6670         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6671 #else
6672         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6673 #endif
6674
6675         for (i = 0; i < fsig->param_count; ++i) {
6676                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6677                         /* These can point to the current method's stack */
6678                         supported_tail_call = FALSE;
6679         }
6680         if (fsig->hasthis && cmethod->klass->valuetype)
6681                 /* this might point to the current method's stack */
6682                 supported_tail_call = FALSE;
6683         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6684                 supported_tail_call = FALSE;
6685         if (cfg->method->save_lmf)
6686                 supported_tail_call = FALSE;
6687         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6688                 supported_tail_call = FALSE;
6689         if (call_opcode != CEE_CALL)
6690                 supported_tail_call = FALSE;
6691
6692         /* Debugging support */
6693 #if 0
6694         if (supported_tail_call) {
6695                 if (!mono_debug_count ())
6696                         supported_tail_call = FALSE;
6697         }
6698 #endif
6699
6700         return supported_tail_call;
6701 }
6702
6703 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6704  * it to the thread local value based on the tls_offset field. Every other kind of access to
6705  * the field causes an assert.
6706  */
6707 static gboolean
6708 is_magic_tls_access (MonoClassField *field)
6709 {
6710         if (strcmp (field->name, "tlsdata"))
6711                 return FALSE;
6712         if (strcmp (field->parent->name, "ThreadLocal`1"))
6713                 return FALSE;
6714         return field->parent->image == mono_defaults.corlib;
6715 }
6716
6717 /* emits the code needed to access a managed tls var (like ThreadStatic)
6718  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6719  * pointer for the current thread.
6720  * Returns the MonoInst* representing the address of the tls var.
6721  */
6722 static MonoInst*
6723 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6724 {
6725         MonoInst *addr;
6726         int static_data_reg, array_reg, dreg;
6727         int offset2_reg, idx_reg;
6728         // inlined access to the tls data
6729         // idx = (offset >> 24) - 1;
6730         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6731         static_data_reg = alloc_ireg (cfg);
6732         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6733         idx_reg = alloc_ireg (cfg);
6734         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6735         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6736         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6737         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6738         array_reg = alloc_ireg (cfg);
6739         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6740         offset2_reg = alloc_ireg (cfg);
6741         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6742         dreg = alloc_ireg (cfg);
6743         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6744         return addr;
6745 }
6746
6747 /*
6748  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6749  * this address is cached per-method in cached_tls_addr.
6750  */
6751 static MonoInst*
6752 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6753 {
6754         MonoInst *load, *addr, *temp, *store, *thread_ins;
6755         MonoClassField *offset_field;
6756
6757         if (*cached_tls_addr) {
6758                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6759                 return addr;
6760         }
6761         thread_ins = mono_get_thread_intrinsic (cfg);
6762         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6763
6764         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6765         if (thread_ins) {
6766                 MONO_ADD_INS (cfg->cbb, thread_ins);
6767         } else {
6768                 MonoMethod *thread_method;
6769                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6770                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6771         }
6772         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6773         addr->klass = mono_class_from_mono_type (tls_field->type);
6774         addr->type = STACK_MP;
6775         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6776         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6777
6778         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6779         return addr;
6780 }
6781
6782 /*
6783  * mono_method_to_ir:
6784  *
6785  *   Translate the .net IL into linear IR.
6786  */
6787 int
6788 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6789                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6790                    guint inline_offset, gboolean is_virtual_call)
6791 {
6792         MonoError error;
6793         MonoInst *ins, **sp, **stack_start;
6794         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6795         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6796         MonoMethod *cmethod, *method_definition;
6797         MonoInst **arg_array;
6798         MonoMethodHeader *header;
6799         MonoImage *image;
6800         guint32 token, ins_flag;
6801         MonoClass *klass;
6802         MonoClass *constrained_call = NULL;
6803         unsigned char *ip, *end, *target, *err_pos;
6804         MonoMethodSignature *sig;
6805         MonoGenericContext *generic_context = NULL;
6806         MonoGenericContainer *generic_container = NULL;
6807         MonoType **param_types;
6808         int i, n, start_new_bblock, dreg;
6809         int num_calls = 0, inline_costs = 0;
6810         int breakpoint_id = 0;
6811         guint num_args;
6812         MonoBoolean security, pinvoke;
6813         MonoSecurityManager* secman = NULL;
6814         MonoDeclSecurityActions actions;
6815         GSList *class_inits = NULL;
6816         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6817         int context_used;
6818         gboolean init_locals, seq_points, skip_dead_blocks;
6819         gboolean disable_inline, sym_seq_points = FALSE;
6820         MonoInst *cached_tls_addr = NULL;
6821         MonoDebugMethodInfo *minfo;
6822         MonoBitSet *seq_point_locs = NULL;
6823         MonoBitSet *seq_point_set_locs = NULL;
6824
6825         disable_inline = is_jit_optimizer_disabled (method);
6826
6827         /* serialization and xdomain stuff may need access to private fields and methods */
6828         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6829         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6830         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6831         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6832         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6833         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6834
6835         dont_verify |= mono_security_smcs_hack_enabled ();
6836
6837         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6838         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6839         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6840         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6841         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6842
6843         image = method->klass->image;
6844         header = mono_method_get_header (method);
6845         if (!header) {
6846                 MonoLoaderError *error;
6847
6848                 if ((error = mono_loader_get_last_error ())) {
6849                         mono_cfg_set_exception (cfg, error->exception_type);
6850                 } else {
6851                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6852                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6853                 }
6854                 goto exception_exit;
6855         }
6856         generic_container = mono_method_get_generic_container (method);
6857         sig = mono_method_signature (method);
6858         num_args = sig->hasthis + sig->param_count;
6859         ip = (unsigned char*)header->code;
6860         cfg->cil_start = ip;
6861         end = ip + header->code_size;
6862         cfg->stat_cil_code_size += header->code_size;
6863
6864         seq_points = cfg->gen_seq_points && cfg->method == method;
6865 #ifdef PLATFORM_ANDROID
6866         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6867 #endif
6868
6869         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6870                 /* We could hit a seq point before attaching to the JIT (#8338) */
6871                 seq_points = FALSE;
6872         }
6873
6874         if (cfg->gen_seq_points && cfg->method == method) {
6875                 minfo = mono_debug_lookup_method (method);
6876                 if (minfo) {
6877                         int i, n_il_offsets;
6878                         int *il_offsets;
6879                         int *line_numbers;
6880
6881                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6882                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6883                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6884                         sym_seq_points = TRUE;
6885                         for (i = 0; i < n_il_offsets; ++i) {
6886                                 if (il_offsets [i] < header->code_size)
6887                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6888                         }
6889                         g_free (il_offsets);
6890                         g_free (line_numbers);
6891                 }
6892         }
6893
6894         /* 
6895          * Methods without init_locals set could cause asserts in various passes
6896          * (#497220). To work around this, we emit dummy initialization opcodes
6897          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
6898          * on some platforms.
6899          */
6900         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
6901                 init_locals = header->init_locals;
6902         else
6903                 init_locals = TRUE;
6904
6905         method_definition = method;
6906         while (method_definition->is_inflated) {
6907                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6908                 method_definition = imethod->declaring;
6909         }
6910
6911         /* SkipVerification is not allowed if core-clr is enabled */
6912         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6913                 dont_verify = TRUE;
6914                 dont_verify_stloc = TRUE;
6915         }
6916
6917         if (sig->is_inflated)
6918                 generic_context = mono_method_get_context (method);
6919         else if (generic_container)
6920                 generic_context = &generic_container->context;
6921         cfg->generic_context = generic_context;
6922
6923         if (!cfg->generic_sharing_context)
6924                 g_assert (!sig->has_type_parameters);
6925
6926         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6927                 g_assert (method->is_inflated);
6928                 g_assert (mono_method_get_context (method)->method_inst);
6929         }
6930         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6931                 g_assert (sig->generic_param_count);
6932
6933         if (cfg->method == method) {
6934                 cfg->real_offset = 0;
6935         } else {
6936                 cfg->real_offset = inline_offset;
6937         }
6938
6939         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6940         cfg->cil_offset_to_bb_len = header->code_size;
6941
6942         cfg->current_method = method;
6943
6944         if (cfg->verbose_level > 2)
6945                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6946
6947         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6948         if (sig->hasthis)
6949                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6950         for (n = 0; n < sig->param_count; ++n)
6951                 param_types [n + sig->hasthis] = sig->params [n];
6952         cfg->arg_types = param_types;
6953
6954         dont_inline = g_list_prepend (dont_inline, method);
6955         if (cfg->method == method) {
6956
6957                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6958                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6959
6960                 /* ENTRY BLOCK */
6961                 NEW_BBLOCK (cfg, start_bblock);
6962                 cfg->bb_entry = start_bblock;
6963                 start_bblock->cil_code = NULL;
6964                 start_bblock->cil_length = 0;
6965 #if defined(__native_client_codegen__)
6966                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6967                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6968                 MONO_ADD_INS (start_bblock, ins);
6969 #endif
6970
6971                 /* EXIT BLOCK */
6972                 NEW_BBLOCK (cfg, end_bblock);
6973                 cfg->bb_exit = end_bblock;
6974                 end_bblock->cil_code = NULL;
6975                 end_bblock->cil_length = 0;
6976                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6977                 g_assert (cfg->num_bblocks == 2);
6978
6979                 arg_array = cfg->args;
6980
6981                 if (header->num_clauses) {
6982                         cfg->spvars = g_hash_table_new (NULL, NULL);
6983                         cfg->exvars = g_hash_table_new (NULL, NULL);
6984                 }
6985                 /* handle exception clauses */
6986                 for (i = 0; i < header->num_clauses; ++i) {
6987                         MonoBasicBlock *try_bb;
6988                         MonoExceptionClause *clause = &header->clauses [i];
6989                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6990                         try_bb->real_offset = clause->try_offset;
6991                         try_bb->try_start = TRUE;
6992                         try_bb->region = ((i + 1) << 8) | clause->flags;
6993                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6994                         tblock->real_offset = clause->handler_offset;
6995                         tblock->flags |= BB_EXCEPTION_HANDLER;
6996
6997                         /*
6998                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6999                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7000                          */
7001                         if (COMPILE_LLVM (cfg))
7002                                 link_bblock (cfg, try_bb, tblock);
7003
7004                         if (*(ip + clause->handler_offset) == CEE_POP)
7005                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7006
7007                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7008                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7009                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7010                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7011                                 MONO_ADD_INS (tblock, ins);
7012
7013                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7014                                         /* finally clauses already have a seq point */
7015                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7016                                         MONO_ADD_INS (tblock, ins);
7017                                 }
7018
7019                                 /* todo: is a fault block unsafe to optimize? */
7020                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7021                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7022                         }
7023
7024
7025                         /*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);
7026                           while (p < end) {
7027                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7028                           }*/
7029                         /* catch and filter blocks get the exception object on the stack */
7030                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7031                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7032                                 MonoInst *dummy_use;
7033
7034                                 /* mostly like handle_stack_args (), but just sets the input args */
7035                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7036                                 tblock->in_scount = 1;
7037                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7038                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7039
7040                                 /* 
7041                                  * Add a dummy use for the exvar so its liveness info will be
7042                                  * correct.
7043                                  */
7044                                 cfg->cbb = tblock;
7045                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7046                                 
7047                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7048                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7049                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7050                                         tblock->real_offset = clause->data.filter_offset;
7051                                         tblock->in_scount = 1;
7052                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7053                                         /* The filter block shares the exvar with the handler block */
7054                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7055                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7056                                         MONO_ADD_INS (tblock, ins);
7057                                 }
7058                         }
7059
7060                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7061                                         clause->data.catch_class &&
7062                                         cfg->generic_sharing_context &&
7063                                         mono_class_check_context_used (clause->data.catch_class)) {
7064                                 /*
7065                                  * In shared generic code with catch
7066                                  * clauses containing type variables
7067                                  * the exception handling code has to
7068                                  * be able to get to the rgctx.
7069                                  * Therefore we have to make sure that
7070                                  * the vtable/mrgctx argument (for
7071                                  * static or generic methods) or the
7072                                  * "this" argument (for non-static
7073                                  * methods) are live.
7074                                  */
7075                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7076                                                 mini_method_get_context (method)->method_inst ||
7077                                                 method->klass->valuetype) {
7078                                         mono_get_vtable_var (cfg);
7079                                 } else {
7080                                         MonoInst *dummy_use;
7081
7082                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7083                                 }
7084                         }
7085                 }
7086         } else {
7087                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7088                 cfg->cbb = start_bblock;
7089                 cfg->args = arg_array;
7090                 mono_save_args (cfg, sig, inline_args);
7091         }
7092
7093         /* FIRST CODE BLOCK */
7094         NEW_BBLOCK (cfg, bblock);
7095         bblock->cil_code = ip;
7096         cfg->cbb = bblock;
7097         cfg->ip = ip;
7098
7099         ADD_BBLOCK (cfg, bblock);
7100
7101         if (cfg->method == method) {
7102                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7103                 if (breakpoint_id) {
7104                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7105                         MONO_ADD_INS (bblock, ins);
7106                 }
7107         }
7108
7109         if (mono_security_cas_enabled ())
7110                 secman = mono_security_manager_get_methods ();
7111
7112         security = (secman && mono_security_method_has_declsec (method));
7113         /* at this point having security doesn't mean we have any code to generate */
7114         if (security && (cfg->method == method)) {
7115                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7116                  * And we do not want to enter the next section (with allocation) if we
7117                  * have nothing to generate */
7118                 security = mono_declsec_get_demands (method, &actions);
7119         }
7120
7121         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7122         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7123         if (pinvoke) {
7124                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7125                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7126                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7127
7128                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7129                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7130                                 pinvoke = FALSE;
7131                         }
7132                         if (custom)
7133                                 mono_custom_attrs_free (custom);
7134
7135                         if (pinvoke) {
7136                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7137                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7138                                         pinvoke = FALSE;
7139                                 }
7140                                 if (custom)
7141                                         mono_custom_attrs_free (custom);
7142                         }
7143                 } else {
7144                         /* not a P/Invoke after all */
7145                         pinvoke = FALSE;
7146                 }
7147         }
7148         
7149         /* we use a separate basic block for the initialization code */
7150         NEW_BBLOCK (cfg, init_localsbb);
7151         cfg->bb_init = init_localsbb;
7152         init_localsbb->real_offset = cfg->real_offset;
7153         start_bblock->next_bb = init_localsbb;
7154         init_localsbb->next_bb = bblock;
7155         link_bblock (cfg, start_bblock, init_localsbb);
7156         link_bblock (cfg, init_localsbb, bblock);
7157                 
7158         cfg->cbb = init_localsbb;
7159
7160         if (cfg->gsharedvt && cfg->method == method) {
7161                 MonoGSharedVtMethodInfo *info;
7162                 MonoInst *var, *locals_var;
7163                 int dreg;
7164
7165                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7166                 info->method = cfg->method;
7167                 info->count_entries = 16;
7168                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7169                 cfg->gsharedvt_info = info;
7170
7171                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7172                 /* prevent it from being register allocated */
7173                 //var->flags |= MONO_INST_VOLATILE;
7174                 cfg->gsharedvt_info_var = var;
7175
7176                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7177                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7178
7179                 /* Allocate locals */
7180                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7181                 /* prevent it from being register allocated */
7182                 //locals_var->flags |= MONO_INST_VOLATILE;
7183                 cfg->gsharedvt_locals_var = locals_var;
7184
7185                 dreg = alloc_ireg (cfg);
7186                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7187
7188                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7189                 ins->dreg = locals_var->dreg;
7190                 ins->sreg1 = dreg;
7191                 MONO_ADD_INS (cfg->cbb, ins);
7192                 cfg->gsharedvt_locals_var_ins = ins;
7193                 
7194                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7195                 /*
7196                 if (init_locals)
7197                         ins->flags |= MONO_INST_INIT;
7198                 */
7199         }
7200
7201         /* at this point we know, if security is TRUE, that some code needs to be generated */
7202         if (security && (cfg->method == method)) {
7203                 MonoInst *args [2];
7204
7205                 cfg->stat_cas_demand_generation++;
7206
7207                 if (actions.demand.blob) {
7208                         /* Add code for SecurityAction.Demand */
7209                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7210                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7211                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7212                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7213                 }
7214                 if (actions.noncasdemand.blob) {
7215                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7216                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7217                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7218                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7219                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7220                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7221                 }
7222                 if (actions.demandchoice.blob) {
7223                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7224                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7225                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7226                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7227                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7228                 }
7229         }
7230
7231         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7232         if (pinvoke) {
7233                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7234         }
7235
7236         if (mono_security_core_clr_enabled ()) {
7237                 /* check if this is native code, e.g. an icall or a p/invoke */
7238                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7239                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7240                         if (wrapped) {
7241                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7242                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7243
7244                                 /* if this ia a native call then it can only be JITted from platform code */
7245                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7246                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7247                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7248                                                         mono_get_exception_method_access ();
7249                                                 emit_throw_exception (cfg, ex);
7250                                         }
7251                                 }
7252                         }
7253                 }
7254         }
7255
7256         CHECK_CFG_EXCEPTION;
7257
7258         if (header->code_size == 0)
7259                 UNVERIFIED;
7260
7261         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7262                 ip = err_pos;
7263                 UNVERIFIED;
7264         }
7265
7266         if (cfg->method == method)
7267                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7268
7269         for (n = 0; n < header->num_locals; ++n) {
7270                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7271                         UNVERIFIED;
7272         }
7273         class_inits = NULL;
7274
7275         /* We force the vtable variable here for all shared methods
7276            for the possibility that they might show up in a stack
7277            trace where their exact instantiation is needed. */
7278         if (cfg->generic_sharing_context && method == cfg->method) {
7279                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7280                                 mini_method_get_context (method)->method_inst ||
7281                                 method->klass->valuetype) {
7282                         mono_get_vtable_var (cfg);
7283                 } else {
7284                         /* FIXME: Is there a better way to do this?
7285                            We need the variable live for the duration
7286                            of the whole method. */
7287                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7288                 }
7289         }
7290
7291         /* add a check for this != NULL to inlined methods */
7292         if (is_virtual_call) {
7293                 MonoInst *arg_ins;
7294
7295                 NEW_ARGLOAD (cfg, arg_ins, 0);
7296                 MONO_ADD_INS (cfg->cbb, arg_ins);
7297                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7298         }
7299
7300         skip_dead_blocks = !dont_verify;
7301         if (skip_dead_blocks) {
7302                 original_bb = bb = mono_basic_block_split (method, &error);
7303                 if (!mono_error_ok (&error)) {
7304                         mono_error_cleanup (&error);
7305                         UNVERIFIED;
7306                 }
7307                 g_assert (bb);
7308         }
7309
7310         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7311         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7312
7313         ins_flag = 0;
7314         start_new_bblock = 0;
7315         cfg->cbb = bblock;
7316         while (ip < end) {
7317                 if (cfg->method == method)
7318                         cfg->real_offset = ip - header->code;
7319                 else
7320                         cfg->real_offset = inline_offset;
7321                 cfg->ip = ip;
7322
7323                 context_used = 0;
7324                 
7325                 if (start_new_bblock) {
7326                         bblock->cil_length = ip - bblock->cil_code;
7327                         if (start_new_bblock == 2) {
7328                                 g_assert (ip == tblock->cil_code);
7329                         } else {
7330                                 GET_BBLOCK (cfg, tblock, ip);
7331                         }
7332                         bblock->next_bb = tblock;
7333                         bblock = tblock;
7334                         cfg->cbb = bblock;
7335                         start_new_bblock = 0;
7336                         for (i = 0; i < bblock->in_scount; ++i) {
7337                                 if (cfg->verbose_level > 3)
7338                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7339                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7340                                 *sp++ = ins;
7341                         }
7342                         if (class_inits)
7343                                 g_slist_free (class_inits);
7344                         class_inits = NULL;
7345                 } else {
7346                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7347                                 link_bblock (cfg, bblock, tblock);
7348                                 if (sp != stack_start) {
7349                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7350                                         sp = stack_start;
7351                                         CHECK_UNVERIFIABLE (cfg);
7352                                 }
7353                                 bblock->next_bb = tblock;
7354                                 bblock = tblock;
7355                                 cfg->cbb = bblock;
7356                                 for (i = 0; i < bblock->in_scount; ++i) {
7357                                         if (cfg->verbose_level > 3)
7358                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7359                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7360                                         *sp++ = ins;
7361                                 }
7362                                 g_slist_free (class_inits);
7363                                 class_inits = NULL;
7364                         }
7365                 }
7366
7367                 if (skip_dead_blocks) {
7368                         int ip_offset = ip - header->code;
7369
7370                         if (ip_offset == bb->end)
7371                                 bb = bb->next;
7372
7373                         if (bb->dead) {
7374                                 int op_size = mono_opcode_size (ip, end);
7375                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7376
7377                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7378
7379                                 if (ip_offset + op_size == bb->end) {
7380                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7381                                         MONO_ADD_INS (bblock, ins);
7382                                         start_new_bblock = 1;
7383                                 }
7384
7385                                 ip += op_size;
7386                                 continue;
7387                         }
7388                 }
7389                 /*
7390                  * Sequence points are points where the debugger can place a breakpoint.
7391                  * Currently, we generate these automatically at points where the IL
7392                  * stack is empty.
7393                  */
7394                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7395                         /*
7396                          * Make methods interruptable at the beginning, and at the targets of
7397                          * backward branches.
7398                          * Also, do this at the start of every bblock in methods with clauses too,
7399                          * to be able to handle instructions with inprecise control flow like
7400                          * throw/endfinally.
7401                          * Backward branches are handled at the end of method-to-ir ().
7402                          */
7403                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7404
7405                         /* Avoid sequence points on empty IL like .volatile */
7406                         // FIXME: Enable this
7407                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7408                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7409                         if (sp != stack_start)
7410                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7411                         MONO_ADD_INS (cfg->cbb, ins);
7412
7413                         if (sym_seq_points)
7414                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7415                 }
7416
7417                 bblock->real_offset = cfg->real_offset;
7418
7419                 if ((cfg->method == method) && cfg->coverage_info) {
7420                         guint32 cil_offset = ip - header->code;
7421                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7422
7423                         /* TODO: Use an increment here */
7424 #if defined(TARGET_X86)
7425                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7426                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7427                         ins->inst_imm = 1;
7428                         MONO_ADD_INS (cfg->cbb, ins);
7429 #else
7430                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7431                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7432 #endif
7433                 }
7434
7435                 if (cfg->verbose_level > 3)
7436                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7437
7438                 switch (*ip) {
7439                 case CEE_NOP:
7440                         if (seq_points && !sym_seq_points && sp != stack_start) {
7441                                 /*
7442                                  * The C# compiler uses these nops to notify the JIT that it should
7443                                  * insert seq points.
7444                                  */
7445                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7446                                 MONO_ADD_INS (cfg->cbb, ins);
7447                         }
7448                         if (cfg->keep_cil_nops)
7449                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7450                         else
7451                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7452                         ip++;
7453                         MONO_ADD_INS (bblock, ins);
7454                         break;
7455                 case CEE_BREAK:
7456                         if (should_insert_brekpoint (cfg->method)) {
7457                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7458                         } else {
7459                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7460                         }
7461                         ip++;
7462                         MONO_ADD_INS (bblock, ins);
7463                         break;
7464                 case CEE_LDARG_0:
7465                 case CEE_LDARG_1:
7466                 case CEE_LDARG_2:
7467                 case CEE_LDARG_3:
7468                         CHECK_STACK_OVF (1);
7469                         n = (*ip)-CEE_LDARG_0;
7470                         CHECK_ARG (n);
7471                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7472                         ip++;
7473                         *sp++ = ins;
7474                         break;
7475                 case CEE_LDLOC_0:
7476                 case CEE_LDLOC_1:
7477                 case CEE_LDLOC_2:
7478                 case CEE_LDLOC_3:
7479                         CHECK_STACK_OVF (1);
7480                         n = (*ip)-CEE_LDLOC_0;
7481                         CHECK_LOCAL (n);
7482                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7483                         ip++;
7484                         *sp++ = ins;
7485                         break;
7486                 case CEE_STLOC_0:
7487                 case CEE_STLOC_1:
7488                 case CEE_STLOC_2:
7489                 case CEE_STLOC_3: {
7490                         CHECK_STACK (1);
7491                         n = (*ip)-CEE_STLOC_0;
7492                         CHECK_LOCAL (n);
7493                         --sp;
7494                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7495                                 UNVERIFIED;
7496                         emit_stloc_ir (cfg, sp, header, n);
7497                         ++ip;
7498                         inline_costs += 1;
7499                         break;
7500                         }
7501                 case CEE_LDARG_S:
7502                         CHECK_OPSIZE (2);
7503                         CHECK_STACK_OVF (1);
7504                         n = ip [1];
7505                         CHECK_ARG (n);
7506                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7507                         *sp++ = ins;
7508                         ip += 2;
7509                         break;
7510                 case CEE_LDARGA_S:
7511                         CHECK_OPSIZE (2);
7512                         CHECK_STACK_OVF (1);
7513                         n = ip [1];
7514                         CHECK_ARG (n);
7515                         NEW_ARGLOADA (cfg, ins, n);
7516                         MONO_ADD_INS (cfg->cbb, ins);
7517                         *sp++ = ins;
7518                         ip += 2;
7519                         break;
7520                 case CEE_STARG_S:
7521                         CHECK_OPSIZE (2);
7522                         CHECK_STACK (1);
7523                         --sp;
7524                         n = ip [1];
7525                         CHECK_ARG (n);
7526                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7527                                 UNVERIFIED;
7528                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7529                         ip += 2;
7530                         break;
7531                 case CEE_LDLOC_S:
7532                         CHECK_OPSIZE (2);
7533                         CHECK_STACK_OVF (1);
7534                         n = ip [1];
7535                         CHECK_LOCAL (n);
7536                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7537                         *sp++ = ins;
7538                         ip += 2;
7539                         break;
7540                 case CEE_LDLOCA_S: {
7541                         unsigned char *tmp_ip;
7542                         CHECK_OPSIZE (2);
7543                         CHECK_STACK_OVF (1);
7544                         CHECK_LOCAL (ip [1]);
7545
7546                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7547                                 ip = tmp_ip;
7548                                 inline_costs += 1;
7549                                 break;
7550                         }
7551
7552                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7553                         *sp++ = ins;
7554                         ip += 2;
7555                         break;
7556                 }
7557                 case CEE_STLOC_S:
7558                         CHECK_OPSIZE (2);
7559                         CHECK_STACK (1);
7560                         --sp;
7561                         CHECK_LOCAL (ip [1]);
7562                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7563                                 UNVERIFIED;
7564                         emit_stloc_ir (cfg, sp, header, ip [1]);
7565                         ip += 2;
7566                         inline_costs += 1;
7567                         break;
7568                 case CEE_LDNULL:
7569                         CHECK_STACK_OVF (1);
7570                         EMIT_NEW_PCONST (cfg, ins, NULL);
7571                         ins->type = STACK_OBJ;
7572                         ++ip;
7573                         *sp++ = ins;
7574                         break;
7575                 case CEE_LDC_I4_M1:
7576                         CHECK_STACK_OVF (1);
7577                         EMIT_NEW_ICONST (cfg, ins, -1);
7578                         ++ip;
7579                         *sp++ = ins;
7580                         break;
7581                 case CEE_LDC_I4_0:
7582                 case CEE_LDC_I4_1:
7583                 case CEE_LDC_I4_2:
7584                 case CEE_LDC_I4_3:
7585                 case CEE_LDC_I4_4:
7586                 case CEE_LDC_I4_5:
7587                 case CEE_LDC_I4_6:
7588                 case CEE_LDC_I4_7:
7589                 case CEE_LDC_I4_8:
7590                         CHECK_STACK_OVF (1);
7591                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7592                         ++ip;
7593                         *sp++ = ins;
7594                         break;
7595                 case CEE_LDC_I4_S:
7596                         CHECK_OPSIZE (2);
7597                         CHECK_STACK_OVF (1);
7598                         ++ip;
7599                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7600                         ++ip;
7601                         *sp++ = ins;
7602                         break;
7603                 case CEE_LDC_I4:
7604                         CHECK_OPSIZE (5);
7605                         CHECK_STACK_OVF (1);
7606                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7607                         ip += 5;
7608                         *sp++ = ins;
7609                         break;
7610                 case CEE_LDC_I8:
7611                         CHECK_OPSIZE (9);
7612                         CHECK_STACK_OVF (1);
7613                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7614                         ins->type = STACK_I8;
7615                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7616                         ++ip;
7617                         ins->inst_l = (gint64)read64 (ip);
7618                         MONO_ADD_INS (bblock, ins);
7619                         ip += 8;
7620                         *sp++ = ins;
7621                         break;
7622                 case CEE_LDC_R4: {
7623                         float *f;
7624                         gboolean use_aotconst = FALSE;
7625
7626 #ifdef TARGET_POWERPC
7627                         /* FIXME: Clean this up */
7628                         if (cfg->compile_aot)
7629                                 use_aotconst = TRUE;
7630 #endif
7631
7632                         /* FIXME: we should really allocate this only late in the compilation process */
7633                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7634                         CHECK_OPSIZE (5);
7635                         CHECK_STACK_OVF (1);
7636
7637                         if (use_aotconst) {
7638                                 MonoInst *cons;
7639                                 int dreg;
7640
7641                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7642
7643                                 dreg = alloc_freg (cfg);
7644                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7645                                 ins->type = STACK_R8;
7646                         } else {
7647                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7648                                 ins->type = STACK_R8;
7649                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7650                                 ins->inst_p0 = f;
7651                                 MONO_ADD_INS (bblock, ins);
7652                         }
7653                         ++ip;
7654                         readr4 (ip, f);
7655                         ip += 4;
7656                         *sp++ = ins;                    
7657                         break;
7658                 }
7659                 case CEE_LDC_R8: {
7660                         double *d;
7661                         gboolean use_aotconst = FALSE;
7662
7663 #ifdef TARGET_POWERPC
7664                         /* FIXME: Clean this up */
7665                         if (cfg->compile_aot)
7666                                 use_aotconst = TRUE;
7667 #endif
7668
7669                         /* FIXME: we should really allocate this only late in the compilation process */
7670                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7671                         CHECK_OPSIZE (9);
7672                         CHECK_STACK_OVF (1);
7673
7674                         if (use_aotconst) {
7675                                 MonoInst *cons;
7676                                 int dreg;
7677
7678                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7679
7680                                 dreg = alloc_freg (cfg);
7681                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7682                                 ins->type = STACK_R8;
7683                         } else {
7684                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7685                                 ins->type = STACK_R8;
7686                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7687                                 ins->inst_p0 = d;
7688                                 MONO_ADD_INS (bblock, ins);
7689                         }
7690                         ++ip;
7691                         readr8 (ip, d);
7692                         ip += 8;
7693                         *sp++ = ins;
7694                         break;
7695                 }
7696                 case CEE_DUP: {
7697                         MonoInst *temp, *store;
7698                         CHECK_STACK (1);
7699                         CHECK_STACK_OVF (1);
7700                         sp--;
7701                         ins = *sp;
7702
7703                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7704                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7705
7706                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7707                         *sp++ = ins;
7708
7709                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7710                         *sp++ = ins;
7711
7712                         ++ip;
7713                         inline_costs += 2;
7714                         break;
7715                 }
7716                 case CEE_POP:
7717                         CHECK_STACK (1);
7718                         ip++;
7719                         --sp;
7720
7721 #ifdef TARGET_X86
7722                         if (sp [0]->type == STACK_R8)
7723                                 /* we need to pop the value from the x86 FP stack */
7724                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7725 #endif
7726                         break;
7727                 case CEE_JMP: {
7728                         MonoCallInst *call;
7729
7730                         INLINE_FAILURE ("jmp");
7731                         GSHAREDVT_FAILURE (*ip);
7732
7733                         CHECK_OPSIZE (5);
7734                         if (stack_start != sp)
7735                                 UNVERIFIED;
7736                         token = read32 (ip + 1);
7737                         /* FIXME: check the signature matches */
7738                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7739
7740                         if (!cmethod || mono_loader_get_last_error ())
7741                                 LOAD_ERROR;
7742  
7743                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7744                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7745
7746                         if (mono_security_cas_enabled ())
7747                                 CHECK_CFG_EXCEPTION;
7748
7749                         if (ARCH_HAVE_OP_TAIL_CALL) {
7750                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7751                                 int i, n;
7752
7753                                 /* Handle tail calls similarly to calls */
7754                                 n = fsig->param_count + fsig->hasthis;
7755
7756                                 DISABLE_AOT (cfg);
7757
7758                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7759                                 call->method = cmethod;
7760                                 call->tail_call = TRUE;
7761                                 call->signature = mono_method_signature (cmethod);
7762                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7763                                 call->inst.inst_p0 = cmethod;
7764                                 for (i = 0; i < n; ++i)
7765                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7766
7767                                 mono_arch_emit_call (cfg, call);
7768                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7769                         } else {
7770                                 for (i = 0; i < num_args; ++i)
7771                                         /* Prevent arguments from being optimized away */
7772                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7773
7774                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7775                                 ins = (MonoInst*)call;
7776                                 ins->inst_p0 = cmethod;
7777                                 MONO_ADD_INS (bblock, ins);
7778                         }
7779
7780                         ip += 5;
7781                         start_new_bblock = 1;
7782                         break;
7783                 }
7784                 case CEE_CALLI:
7785                 case CEE_CALL:
7786                 case CEE_CALLVIRT: {
7787                         MonoInst *addr = NULL;
7788                         MonoMethodSignature *fsig = NULL;
7789                         int array_rank = 0;
7790                         int virtual = *ip == CEE_CALLVIRT;
7791                         int calli = *ip == CEE_CALLI;
7792                         gboolean pass_imt_from_rgctx = FALSE;
7793                         MonoInst *imt_arg = NULL;
7794                         MonoInst *keep_this_alive = NULL;
7795                         gboolean pass_vtable = FALSE;
7796                         gboolean pass_mrgctx = FALSE;
7797                         MonoInst *vtable_arg = NULL;
7798                         gboolean check_this = FALSE;
7799                         gboolean supported_tail_call = FALSE;
7800                         gboolean tail_call = FALSE;
7801                         gboolean need_seq_point = FALSE;
7802                         guint32 call_opcode = *ip;
7803                         gboolean emit_widen = TRUE;
7804                         gboolean push_res = TRUE;
7805                         gboolean skip_ret = FALSE;
7806                         gboolean delegate_invoke = FALSE;
7807
7808                         CHECK_OPSIZE (5);
7809                         token = read32 (ip + 1);
7810
7811                         ins = NULL;
7812
7813                         if (calli) {
7814                                 //GSHAREDVT_FAILURE (*ip);
7815                                 cmethod = NULL;
7816                                 CHECK_STACK (1);
7817                                 --sp;
7818                                 addr = *sp;
7819                                 fsig = mini_get_signature (method, token, generic_context);
7820                                 n = fsig->param_count + fsig->hasthis;
7821
7822                                 if (method->dynamic && fsig->pinvoke) {
7823                                         MonoInst *args [3];
7824
7825                                         /*
7826                                          * This is a call through a function pointer using a pinvoke
7827                                          * signature. Have to create a wrapper and call that instead.
7828                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7829                                          * instead based on the signature.
7830                                          */
7831                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7832                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7833                                         args [2] = addr;
7834                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7835                                 }
7836                         } else {
7837                                 MonoMethod *cil_method;
7838
7839                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7840                                 cil_method = cmethod;
7841                                 
7842                                 if (constrained_call) {
7843                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7844                                                 if (cfg->verbose_level > 2)
7845                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7846                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7847                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7848                                                           cfg->generic_sharing_context)) {
7849                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7850                                                 }
7851                                         } else {
7852                                                 if (cfg->verbose_level > 2)
7853                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7854
7855                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7856                                                         /* 
7857                                                          * This is needed since get_method_constrained can't find 
7858                                                          * the method in klass representing a type var.
7859                                                          * The type var is guaranteed to be a reference type in this
7860                                                          * case.
7861                                                          */
7862                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7863                                                                 g_assert (!cmethod->klass->valuetype);
7864                                                 } else {
7865                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7866                                                 }
7867                                         }
7868                                 }
7869                                         
7870                                 if (!cmethod || mono_loader_get_last_error ())
7871                                         LOAD_ERROR;
7872                                 if (!dont_verify && !cfg->skip_visibility) {
7873                                         MonoMethod *target_method = cil_method;
7874                                         if (method->is_inflated) {
7875                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7876                                         }
7877                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7878                                                 !mono_method_can_access_method (method, cil_method))
7879                                                 METHOD_ACCESS_FAILURE;
7880                                 }
7881
7882                                 if (mono_security_core_clr_enabled ())
7883                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7884
7885                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7886                                         /* MS.NET seems to silently convert this to a callvirt */
7887                                         virtual = 1;
7888
7889                                 {
7890                                         /*
7891                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7892                                          * converts to a callvirt.
7893                                          *
7894                                          * tests/bug-515884.il is an example of this behavior
7895                                          */
7896                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7897                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7898                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7899                                                 virtual = 1;
7900                                 }
7901
7902                                 if (!cmethod->klass->inited)
7903                                         if (!mono_class_init (cmethod->klass))
7904                                                 TYPE_LOAD_ERROR (cmethod->klass);
7905
7906                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7907                                     mini_class_is_system_array (cmethod->klass)) {
7908                                         array_rank = cmethod->klass->rank;
7909                                         fsig = mono_method_signature (cmethod);
7910                                 } else {
7911                                         fsig = mono_method_signature (cmethod);
7912
7913                                         if (!fsig)
7914                                                 LOAD_ERROR;
7915
7916                                         if (fsig->pinvoke) {
7917                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7918                                                         check_for_pending_exc, cfg->compile_aot);
7919                                                 fsig = mono_method_signature (wrapper);
7920                                         } else if (constrained_call) {
7921                                                 fsig = mono_method_signature (cmethod);
7922                                         } else {
7923                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7924                                         }
7925                                 }
7926
7927                                 mono_save_token_info (cfg, image, token, cil_method);
7928
7929                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7930                                         /*
7931                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7932                                          * foo (bar (), baz ())
7933                                          * works correctly. MS does this also:
7934                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7935                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7936                                          * even for simple cases, like:
7937                                          * int i = foo ();
7938                                          */
7939                                         /* Special case a few common successor opcodes */
7940                                         if (!(ip + 5 < end && (ip [5] == CEE_POP || ip [5] == CEE_NOP)) && !(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
7941                                                 need_seq_point = TRUE;
7942                                 }
7943
7944                                 n = fsig->param_count + fsig->hasthis;
7945
7946                                 /* Don't support calls made using type arguments for now */
7947                                 /*
7948                                 if (cfg->gsharedvt) {
7949                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7950                                                 GSHAREDVT_FAILURE (*ip);
7951                                 }
7952                                 */
7953
7954                                 if (mono_security_cas_enabled ()) {
7955                                         if (check_linkdemand (cfg, method, cmethod))
7956                                                 INLINE_FAILURE ("linkdemand");
7957                                         CHECK_CFG_EXCEPTION;
7958                                 }
7959
7960                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7961                                         g_assert_not_reached ();
7962                         }
7963
7964                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7965                                 UNVERIFIED;
7966
7967                         if (!cfg->generic_sharing_context && cmethod)
7968                                 g_assert (!mono_method_check_context_used (cmethod));
7969
7970                         CHECK_STACK (n);
7971
7972                         //g_assert (!virtual || fsig->hasthis);
7973
7974                         sp -= n;
7975
7976                         if (constrained_call) {
7977                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7978                                         /*
7979                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7980                                          */
7981                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7982                                                 /* The 'Own method' case below */
7983                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7984                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7985                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7986                                                            (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || mini_is_gsharedvt_type (cfg, fsig->ret)) &&
7987                                                            (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
7988                                                 MonoInst *args [16];
7989
7990                                                 /*
7991                                                  * This case handles calls to
7992                                                  * - object:ToString()/Equals()/GetHashCode(),
7993                                                  * - System.IComparable<T>:CompareTo()
7994                                                  * - System.IEquatable<T>:Equals ()
7995                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7996                                                  */
7997
7998                                                 args [0] = sp [0];
7999                                                 if (mono_method_check_context_used (cmethod))
8000                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
8001                                                 else
8002                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
8003                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
8004
8005                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
8006                                                 if (fsig->hasthis && fsig->param_count) {
8007                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
8008                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
8009                                                         ins->dreg = alloc_preg (cfg);
8010                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
8011                                                         MONO_ADD_INS (cfg->cbb, ins);
8012                                                         args [4] = ins;
8013
8014                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
8015                                                                 int addr_reg;
8016
8017                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
8018
8019                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
8020                                                                 addr_reg = ins->dreg;
8021                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8022                                                         } else {
8023                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8024                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8025                                                         }
8026                                                 } else {
8027                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8028                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8029                                                 }
8030                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8031                                                 emit_widen = FALSE;
8032
8033                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8034                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8035                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
8036                                                         MonoInst *add;
8037
8038                                                         /* Unbox */
8039                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8040                                                         MONO_ADD_INS (cfg->cbb, add);
8041                                                         /* Load value */
8042                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8043                                                         MONO_ADD_INS (cfg->cbb, ins);
8044                                                         /* ins represents the call result */
8045                                                 }
8046
8047                                                 goto call_end;
8048                                         } else {
8049                                                 GSHAREDVT_FAILURE (*ip);
8050                                         }
8051                                 }
8052                                 /*
8053                                  * We have the `constrained.' prefix opcode.
8054                                  */
8055                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8056                                         /*
8057                                          * The type parameter is instantiated as a valuetype,
8058                                          * but that type doesn't override the method we're
8059                                          * calling, so we need to box `this'.
8060                                          */
8061                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8062                                         ins->klass = constrained_call;
8063                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8064                                         CHECK_CFG_EXCEPTION;
8065                                 } else if (!constrained_call->valuetype) {
8066                                         int dreg = alloc_ireg_ref (cfg);
8067
8068                                         /*
8069                                          * The type parameter is instantiated as a reference
8070                                          * type.  We have a managed pointer on the stack, so
8071                                          * we need to dereference it here.
8072                                          */
8073                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8074                                         ins->type = STACK_OBJ;
8075                                         sp [0] = ins;
8076                                 } else {
8077                                         if (cmethod->klass->valuetype) {
8078                                                 /* Own method */
8079                                         } else {
8080                                                 /* Interface method */
8081                                                 int ioffset, slot;
8082
8083                                                 mono_class_setup_vtable (constrained_call);
8084                                                 CHECK_TYPELOAD (constrained_call);
8085                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8086                                                 if (ioffset == -1)
8087                                                         TYPE_LOAD_ERROR (constrained_call);
8088                                                 slot = mono_method_get_vtable_slot (cmethod);
8089                                                 if (slot == -1)
8090                                                         TYPE_LOAD_ERROR (cmethod->klass);
8091                                                 cmethod = constrained_call->vtable [ioffset + slot];
8092
8093                                                 if (cmethod->klass == mono_defaults.enum_class) {
8094                                                         /* Enum implements some interfaces, so treat this as the first case */
8095                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8096                                                         ins->klass = constrained_call;
8097                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8098                                                         CHECK_CFG_EXCEPTION;
8099                                                 }
8100                                         }
8101                                         virtual = 0;
8102                                 }
8103                                 constrained_call = NULL;
8104                         }
8105
8106                         if (!calli && check_call_signature (cfg, fsig, sp))
8107                                 UNVERIFIED;
8108
8109 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8110                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8111                                 delegate_invoke = TRUE;
8112 #endif
8113
8114                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8115                                 bblock = cfg->cbb;
8116                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8117                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8118                                         emit_widen = FALSE;
8119                                 }
8120
8121                                 goto call_end;
8122                         }
8123
8124                         /* 
8125                          * If the callee is a shared method, then its static cctor
8126                          * might not get called after the call was patched.
8127                          */
8128                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8129                                 emit_generic_class_init (cfg, cmethod->klass);
8130                                 CHECK_TYPELOAD (cmethod->klass);
8131                         }
8132
8133                         if (cmethod)
8134                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8135
8136                         if (cfg->generic_sharing_context && cmethod) {
8137                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8138
8139                                 context_used = mini_method_check_context_used (cfg, cmethod);
8140
8141                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8142                                         /* Generic method interface
8143                                            calls are resolved via a
8144                                            helper function and don't
8145                                            need an imt. */
8146                                         if (!cmethod_context || !cmethod_context->method_inst)
8147                                                 pass_imt_from_rgctx = TRUE;
8148                                 }
8149
8150                                 /*
8151                                  * If a shared method calls another
8152                                  * shared method then the caller must
8153                                  * have a generic sharing context
8154                                  * because the magic trampoline
8155                                  * requires it.  FIXME: We shouldn't
8156                                  * have to force the vtable/mrgctx
8157                                  * variable here.  Instead there
8158                                  * should be a flag in the cfg to
8159                                  * request a generic sharing context.
8160                                  */
8161                                 if (context_used &&
8162                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8163                                         mono_get_vtable_var (cfg);
8164                         }
8165
8166                         if (pass_vtable) {
8167                                 if (context_used) {
8168                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8169                                 } else {
8170                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8171
8172                                         CHECK_TYPELOAD (cmethod->klass);
8173                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8174                                 }
8175                         }
8176
8177                         if (pass_mrgctx) {
8178                                 g_assert (!vtable_arg);
8179
8180                                 if (!cfg->compile_aot) {
8181                                         /* 
8182                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8183                                          * for type load errors before.
8184                                          */
8185                                         mono_class_setup_vtable (cmethod->klass);
8186                                         CHECK_TYPELOAD (cmethod->klass);
8187                                 }
8188
8189                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8190
8191                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8192                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8193                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8194                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8195                                         if (virtual)
8196                                                 check_this = TRUE;
8197                                         virtual = 0;
8198                                 }
8199                         }
8200
8201                         if (pass_imt_from_rgctx) {
8202                                 g_assert (!pass_vtable);
8203                                 g_assert (cmethod);
8204
8205                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8206                                         cmethod, MONO_RGCTX_INFO_METHOD);
8207                         }
8208
8209                         if (check_this)
8210                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8211
8212                         /* Calling virtual generic methods */
8213                         if (cmethod && virtual && 
8214                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8215                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8216                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8217                             fsig->generic_param_count && 
8218                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8219                                 MonoInst *this_temp, *this_arg_temp, *store;
8220                                 MonoInst *iargs [4];
8221                                 gboolean use_imt = FALSE;
8222
8223                                 g_assert (fsig->is_inflated);
8224
8225                                 /* Prevent inlining of methods that contain indirect calls */
8226                                 INLINE_FAILURE ("virtual generic call");
8227
8228                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8229                                         GSHAREDVT_FAILURE (*ip);
8230
8231 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8232                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8233                                         use_imt = TRUE;
8234 #endif
8235
8236                                 if (use_imt) {
8237                                         g_assert (!imt_arg);
8238                                         if (!context_used)
8239                                                 g_assert (cmethod->is_inflated);
8240                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8241                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8242                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8243                                 } else {
8244                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8245                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8246                                         MONO_ADD_INS (bblock, store);
8247
8248                                         /* FIXME: This should be a managed pointer */
8249                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8250
8251                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8252                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8253                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8254                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8255                                         addr = mono_emit_jit_icall (cfg,
8256                                                                                                 mono_helper_compile_generic_method, iargs);
8257
8258                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8259
8260                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8261                                 }
8262
8263                                 goto call_end;
8264                         }
8265
8266                         /*
8267                          * Implement a workaround for the inherent races involved in locking:
8268                          * Monitor.Enter ()
8269                          * try {
8270                          * } finally {
8271                          *    Monitor.Exit ()
8272                          * }
8273                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8274                          * try block, the Exit () won't be executed, see:
8275                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8276                          * To work around this, we extend such try blocks to include the last x bytes
8277                          * of the Monitor.Enter () call.
8278                          */
8279                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8280                                 MonoBasicBlock *tbb;
8281
8282                                 GET_BBLOCK (cfg, tbb, ip + 5);
8283                                 /* 
8284                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8285                                  * from Monitor.Enter like ArgumentNullException.
8286                                  */
8287                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8288                                         /* Mark this bblock as needing to be extended */
8289                                         tbb->extend_try_block = TRUE;
8290                                 }
8291                         }
8292
8293                         /* Conversion to a JIT intrinsic */
8294                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8295                                 bblock = cfg->cbb;
8296                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8297                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8298                                         emit_widen = FALSE;
8299                                 }
8300                                 goto call_end;
8301                         }
8302
8303                         /* Inlining */
8304                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8305                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8306                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8307                                  !g_list_find (dont_inline, cmethod)) {
8308                                 int costs;
8309                                 gboolean always = FALSE;
8310
8311                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8312                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8313                                         /* Prevent inlining of methods that call wrappers */
8314                                         INLINE_FAILURE ("wrapper call");
8315                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8316                                         always = TRUE;
8317                                 }
8318
8319                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8320                                 if (costs) {
8321                                         cfg->real_offset += 5;
8322                                         bblock = cfg->cbb;
8323
8324                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8325                                                 /* *sp is already set by inline_method */
8326                                                 sp++;
8327                                                 push_res = FALSE;
8328                                         }
8329
8330                                         inline_costs += costs;
8331
8332                                         goto call_end;
8333                                 }
8334                         }
8335
8336                         /* Tail recursion elimination */
8337                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8338                                 gboolean has_vtargs = FALSE;
8339                                 int i;
8340
8341                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8342                                 INLINE_FAILURE ("tail call");
8343
8344                                 /* keep it simple */
8345                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8346                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8347                                                 has_vtargs = TRUE;
8348                                 }
8349
8350                                 if (!has_vtargs) {
8351                                         for (i = 0; i < n; ++i)
8352                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8353                                         MONO_INST_NEW (cfg, ins, OP_BR);
8354                                         MONO_ADD_INS (bblock, ins);
8355                                         tblock = start_bblock->out_bb [0];
8356                                         link_bblock (cfg, bblock, tblock);
8357                                         ins->inst_target_bb = tblock;
8358                                         start_new_bblock = 1;
8359
8360                                         /* skip the CEE_RET, too */
8361                                         if (ip_in_bb (cfg, bblock, ip + 5))
8362                                                 skip_ret = TRUE;
8363                                         push_res = FALSE;
8364                                         goto call_end;
8365                                 }
8366                         }
8367
8368                         inline_costs += 10 * num_calls++;
8369
8370                         /*
8371                          * Making generic calls out of gsharedvt methods.
8372                          */
8373                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8374                                 MonoRgctxInfoType info_type;
8375
8376                                 if (virtual) {
8377                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8378                                                 //GSHAREDVT_FAILURE (*ip);
8379                                         // disable for possible remoting calls
8380                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8381                                                 GSHAREDVT_FAILURE (*ip);
8382                                         if (fsig->generic_param_count) {
8383                                                 /* virtual generic call */
8384                                                 g_assert (mono_use_imt);
8385                                                 g_assert (!imt_arg);
8386                                                 /* Same as the virtual generic case above */
8387                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8388                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8389                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8390                                                 vtable_arg = NULL;
8391                                         }
8392                                 }
8393
8394                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8395                                         /* test_0_multi_dim_arrays () in gshared.cs */
8396                                         GSHAREDVT_FAILURE (*ip);
8397
8398                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8399                                         keep_this_alive = sp [0];
8400
8401                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8402                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8403                                 else
8404                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8405                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8406
8407                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8408                                 goto call_end;
8409                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8410                                 /*
8411                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8412                                  */
8413                                 MonoInst *callee = addr;
8414
8415                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8416                                         /* Not tested */
8417                                         GSHAREDVT_FAILURE (*ip);
8418
8419                                 addr = emit_get_rgctx_sig (cfg, context_used,
8420                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8421                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8422                                 goto call_end;
8423                         }
8424
8425                         /* Generic sharing */
8426                         /* FIXME: only do this for generic methods if
8427                            they are not shared! */
8428                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8429                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8430                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8431                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8432                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8433                                 INLINE_FAILURE ("gshared");
8434
8435                                 g_assert (cfg->generic_sharing_context && cmethod);
8436                                 g_assert (!addr);
8437
8438                                 /*
8439                                  * We are compiling a call to a
8440                                  * generic method from shared code,
8441                                  * which means that we have to look up
8442                                  * the method in the rgctx and do an
8443                                  * indirect call.
8444                                  */
8445                                 if (fsig->hasthis)
8446                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8447
8448                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8449                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8450                                 goto call_end;
8451                         }
8452
8453                         /* Indirect calls */
8454                         if (addr) {
8455                                 if (call_opcode == CEE_CALL)
8456                                         g_assert (context_used);
8457                                 else if (call_opcode == CEE_CALLI)
8458                                         g_assert (!vtable_arg);
8459                                 else
8460                                         /* FIXME: what the hell is this??? */
8461                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8462                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8463
8464                                 /* Prevent inlining of methods with indirect calls */
8465                                 INLINE_FAILURE ("indirect call");
8466
8467                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8468                                         int info_type;
8469                                         gpointer info_data;
8470
8471                                         /* 
8472                                          * Instead of emitting an indirect call, emit a direct call
8473                                          * with the contents of the aotconst as the patch info.
8474                                          */
8475                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8476                                                 info_type = addr->inst_c1;
8477                                                 info_data = addr->inst_p0;
8478                                         } else {
8479                                                 info_type = addr->inst_right->inst_c1;
8480                                                 info_data = addr->inst_right->inst_left;
8481                                         }
8482                                         
8483                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8484                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8485                                                 NULLIFY_INS (addr);
8486                                                 goto call_end;
8487                                         }
8488                                 }
8489                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8490                                 goto call_end;
8491                         }
8492                                         
8493                         /* Array methods */
8494                         if (array_rank) {
8495                                 MonoInst *addr;
8496
8497                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8498                                         MonoInst *val = sp [fsig->param_count];
8499
8500                                         if (val->type == STACK_OBJ) {
8501                                                 MonoInst *iargs [2];
8502
8503                                                 iargs [0] = sp [0];
8504                                                 iargs [1] = val;
8505                                                 
8506                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8507                                         }
8508                                         
8509                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8510                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8511                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8512                                                 emit_write_barrier (cfg, addr, val);
8513                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8514                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8515
8516                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8517                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8518                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8519                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8520                                         CHECK_TYPELOAD (cmethod->klass);
8521                                         
8522                                         readonly = FALSE;
8523                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8524                                         ins = addr;
8525                                 } else {
8526                                         g_assert_not_reached ();
8527                                 }
8528
8529                                 emit_widen = FALSE;
8530                                 goto call_end;
8531                         }
8532
8533                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8534                         if (ins)
8535                                 goto call_end;
8536
8537                         /* Tail prefix / tail call optimization */
8538
8539                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8540                         /* FIXME: runtime generic context pointer for jumps? */
8541                         /* FIXME: handle this for generic sharing eventually */
8542                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8543                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8544                                 supported_tail_call = TRUE;
8545
8546                         if (supported_tail_call) {
8547                                 MonoCallInst *call;
8548
8549                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8550                                 INLINE_FAILURE ("tail call");
8551
8552                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8553
8554                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8555                                         /* Handle tail calls similarly to normal calls */
8556                                         tail_call = TRUE;
8557                                 } else {
8558                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8559                                         call->tail_call = TRUE;
8560                                         call->method = cmethod;
8561                                         call->signature = mono_method_signature (cmethod);
8562
8563                                         /*
8564                                          * We implement tail calls by storing the actual arguments into the 
8565                                          * argument variables, then emitting a CEE_JMP.
8566                                          */
8567                                         for (i = 0; i < n; ++i) {
8568                                                 /* Prevent argument from being register allocated */
8569                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8570                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8571                                         }
8572                                         ins = (MonoInst*)call;
8573                                         ins->inst_p0 = cmethod;
8574                                         ins->inst_p1 = arg_array [0];
8575                                         MONO_ADD_INS (bblock, ins);
8576                                         link_bblock (cfg, bblock, end_bblock);                  
8577                                         start_new_bblock = 1;
8578
8579                                         // FIXME: Eliminate unreachable epilogs
8580
8581                                         /*
8582                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8583                                          * only reachable from this call.
8584                                          */
8585                                         GET_BBLOCK (cfg, tblock, ip + 5);
8586                                         if (tblock == bblock || tblock->in_count == 0)
8587                                                 skip_ret = TRUE;
8588                                         push_res = FALSE;
8589
8590                                         goto call_end;
8591                                 }
8592                         }
8593
8594                         /* 
8595                          * Synchronized wrappers.
8596                          * Its hard to determine where to replace a method with its synchronized
8597                          * wrapper without causing an infinite recursion. The current solution is
8598                          * to add the synchronized wrapper in the trampolines, and to
8599                          * change the called method to a dummy wrapper, and resolve that wrapper
8600                          * to the real method in mono_jit_compile_method ().
8601                          */
8602                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8603                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8604                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8605                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8606                         }
8607
8608                         /* Common call */
8609                         INLINE_FAILURE ("call");
8610                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8611                                                                                           imt_arg, vtable_arg);
8612
8613                         if (tail_call) {
8614                                 link_bblock (cfg, bblock, end_bblock);                  
8615                                 start_new_bblock = 1;
8616
8617                                 // FIXME: Eliminate unreachable epilogs
8618
8619                                 /*
8620                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8621                                  * only reachable from this call.
8622                                  */
8623                                 GET_BBLOCK (cfg, tblock, ip + 5);
8624                                 if (tblock == bblock || tblock->in_count == 0)
8625                                         skip_ret = TRUE;
8626                                 push_res = FALSE;
8627                         }
8628
8629                         call_end:
8630
8631                         /* End of call, INS should contain the result of the call, if any */
8632
8633                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8634                                 g_assert (ins);
8635                                 if (emit_widen)
8636                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8637                                 else
8638                                         *sp++ = ins;
8639                         }
8640
8641                         if (keep_this_alive) {
8642                                 MonoInst *dummy_use;
8643
8644                                 /* See mono_emit_method_call_full () */
8645                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8646                         }
8647
8648                         CHECK_CFG_EXCEPTION;
8649
8650                         ip += 5;
8651                         if (skip_ret) {
8652                                 g_assert (*ip == CEE_RET);
8653                                 ip += 1;
8654                         }
8655                         ins_flag = 0;
8656                         constrained_call = NULL;
8657                         if (need_seq_point)
8658                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8659                         break;
8660                 }
8661                 case CEE_RET:
8662                         if (cfg->method != method) {
8663                                 /* return from inlined method */
8664                                 /* 
8665                                  * If in_count == 0, that means the ret is unreachable due to
8666                                  * being preceeded by a throw. In that case, inline_method () will
8667                                  * handle setting the return value 
8668                                  * (test case: test_0_inline_throw ()).
8669                                  */
8670                                 if (return_var && cfg->cbb->in_count) {
8671                                         MonoType *ret_type = mono_method_signature (method)->ret;
8672
8673                                         MonoInst *store;
8674                                         CHECK_STACK (1);
8675                                         --sp;
8676
8677                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8678                                                 UNVERIFIED;
8679
8680                                         //g_assert (returnvar != -1);
8681                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8682                                         cfg->ret_var_set = TRUE;
8683                                 } 
8684                         } else {
8685                                 if (cfg->lmf_var && cfg->cbb->in_count)
8686                                         emit_pop_lmf (cfg);
8687
8688                                 if (cfg->ret) {
8689                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8690
8691                                         if (seq_points && !sym_seq_points) {
8692                                                 /* 
8693                                                  * Place a seq point here too even through the IL stack is not
8694                                                  * empty, so a step over on
8695                                                  * call <FOO>
8696                                                  * ret
8697                                                  * will work correctly.
8698                                                  */
8699                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8700                                                 MONO_ADD_INS (cfg->cbb, ins);
8701                                         }
8702
8703                                         g_assert (!return_var);
8704                                         CHECK_STACK (1);
8705                                         --sp;
8706
8707                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8708                                                 UNVERIFIED;
8709
8710                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8711                                                 MonoInst *ret_addr;
8712
8713                                                 if (!cfg->vret_addr) {
8714                                                         MonoInst *ins;
8715
8716                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8717                                                 } else {
8718                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8719
8720                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8721                                                         ins->klass = mono_class_from_mono_type (ret_type);
8722                                                 }
8723                                         } else {
8724 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8725                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8726                                                         MonoInst *iargs [1];
8727                                                         MonoInst *conv;
8728
8729                                                         iargs [0] = *sp;
8730                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8731                                                         mono_arch_emit_setret (cfg, method, conv);
8732                                                 } else {
8733                                                         mono_arch_emit_setret (cfg, method, *sp);
8734                                                 }
8735 #else
8736                                                 mono_arch_emit_setret (cfg, method, *sp);
8737 #endif
8738                                         }
8739                                 }
8740                         }
8741                         if (sp != stack_start)
8742                                 UNVERIFIED;
8743                         MONO_INST_NEW (cfg, ins, OP_BR);
8744                         ip++;
8745                         ins->inst_target_bb = end_bblock;
8746                         MONO_ADD_INS (bblock, ins);
8747                         link_bblock (cfg, bblock, end_bblock);
8748                         start_new_bblock = 1;
8749                         break;
8750                 case CEE_BR_S:
8751                         CHECK_OPSIZE (2);
8752                         MONO_INST_NEW (cfg, ins, OP_BR);
8753                         ip++;
8754                         target = ip + 1 + (signed char)(*ip);
8755                         ++ip;
8756                         GET_BBLOCK (cfg, tblock, target);
8757                         link_bblock (cfg, bblock, tblock);
8758                         ins->inst_target_bb = tblock;
8759                         if (sp != stack_start) {
8760                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8761                                 sp = stack_start;
8762                                 CHECK_UNVERIFIABLE (cfg);
8763                         }
8764                         MONO_ADD_INS (bblock, ins);
8765                         start_new_bblock = 1;
8766                         inline_costs += BRANCH_COST;
8767                         break;
8768                 case CEE_BEQ_S:
8769                 case CEE_BGE_S:
8770                 case CEE_BGT_S:
8771                 case CEE_BLE_S:
8772                 case CEE_BLT_S:
8773                 case CEE_BNE_UN_S:
8774                 case CEE_BGE_UN_S:
8775                 case CEE_BGT_UN_S:
8776                 case CEE_BLE_UN_S:
8777                 case CEE_BLT_UN_S:
8778                         CHECK_OPSIZE (2);
8779                         CHECK_STACK (2);
8780                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8781                         ip++;
8782                         target = ip + 1 + *(signed char*)ip;
8783                         ip++;
8784
8785                         ADD_BINCOND (NULL);
8786
8787                         sp = stack_start;
8788                         inline_costs += BRANCH_COST;
8789                         break;
8790                 case CEE_BR:
8791                         CHECK_OPSIZE (5);
8792                         MONO_INST_NEW (cfg, ins, OP_BR);
8793                         ip++;
8794
8795                         target = ip + 4 + (gint32)read32(ip);
8796                         ip += 4;
8797                         GET_BBLOCK (cfg, tblock, target);
8798                         link_bblock (cfg, bblock, tblock);
8799                         ins->inst_target_bb = tblock;
8800                         if (sp != stack_start) {
8801                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8802                                 sp = stack_start;
8803                                 CHECK_UNVERIFIABLE (cfg);
8804                         }
8805
8806                         MONO_ADD_INS (bblock, ins);
8807
8808                         start_new_bblock = 1;
8809                         inline_costs += BRANCH_COST;
8810                         break;
8811                 case CEE_BRFALSE_S:
8812                 case CEE_BRTRUE_S:
8813                 case CEE_BRFALSE:
8814                 case CEE_BRTRUE: {
8815                         MonoInst *cmp;
8816                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8817                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8818                         guint32 opsize = is_short ? 1 : 4;
8819
8820                         CHECK_OPSIZE (opsize);
8821                         CHECK_STACK (1);
8822                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8823                                 UNVERIFIED;
8824                         ip ++;
8825                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8826                         ip += opsize;
8827
8828                         sp--;
8829
8830                         GET_BBLOCK (cfg, tblock, target);
8831                         link_bblock (cfg, bblock, tblock);
8832                         GET_BBLOCK (cfg, tblock, ip);
8833                         link_bblock (cfg, bblock, tblock);
8834
8835                         if (sp != stack_start) {
8836                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8837                                 CHECK_UNVERIFIABLE (cfg);
8838                         }
8839
8840                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8841                         cmp->sreg1 = sp [0]->dreg;
8842                         type_from_op (cmp, sp [0], NULL);
8843                         CHECK_TYPE (cmp);
8844
8845 #if SIZEOF_REGISTER == 4
8846                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8847                                 /* Convert it to OP_LCOMPARE */
8848                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8849                                 ins->type = STACK_I8;
8850                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8851                                 ins->inst_l = 0;
8852                                 MONO_ADD_INS (bblock, ins);
8853                                 cmp->opcode = OP_LCOMPARE;
8854                                 cmp->sreg2 = ins->dreg;
8855                         }
8856 #endif
8857                         MONO_ADD_INS (bblock, cmp);
8858
8859                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8860                         type_from_op (ins, sp [0], NULL);
8861                         MONO_ADD_INS (bblock, ins);
8862                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8863                         GET_BBLOCK (cfg, tblock, target);
8864                         ins->inst_true_bb = tblock;
8865                         GET_BBLOCK (cfg, tblock, ip);
8866                         ins->inst_false_bb = tblock;
8867                         start_new_bblock = 2;
8868
8869                         sp = stack_start;
8870                         inline_costs += BRANCH_COST;
8871                         break;
8872                 }
8873                 case CEE_BEQ:
8874                 case CEE_BGE:
8875                 case CEE_BGT:
8876                 case CEE_BLE:
8877                 case CEE_BLT:
8878                 case CEE_BNE_UN:
8879                 case CEE_BGE_UN:
8880                 case CEE_BGT_UN:
8881                 case CEE_BLE_UN:
8882                 case CEE_BLT_UN:
8883                         CHECK_OPSIZE (5);
8884                         CHECK_STACK (2);
8885                         MONO_INST_NEW (cfg, ins, *ip);
8886                         ip++;
8887                         target = ip + 4 + (gint32)read32(ip);
8888                         ip += 4;
8889
8890                         ADD_BINCOND (NULL);
8891
8892                         sp = stack_start;
8893                         inline_costs += BRANCH_COST;
8894                         break;
8895                 case CEE_SWITCH: {
8896                         MonoInst *src1;
8897                         MonoBasicBlock **targets;
8898                         MonoBasicBlock *default_bblock;
8899                         MonoJumpInfoBBTable *table;
8900                         int offset_reg = alloc_preg (cfg);
8901                         int target_reg = alloc_preg (cfg);
8902                         int table_reg = alloc_preg (cfg);
8903                         int sum_reg = alloc_preg (cfg);
8904                         gboolean use_op_switch;
8905
8906                         CHECK_OPSIZE (5);
8907                         CHECK_STACK (1);
8908                         n = read32 (ip + 1);
8909                         --sp;
8910                         src1 = sp [0];
8911                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8912                                 UNVERIFIED;
8913
8914                         ip += 5;
8915                         CHECK_OPSIZE (n * sizeof (guint32));
8916                         target = ip + n * sizeof (guint32);
8917
8918                         GET_BBLOCK (cfg, default_bblock, target);
8919                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8920
8921                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8922                         for (i = 0; i < n; ++i) {
8923                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8924                                 targets [i] = tblock;
8925                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8926                                 ip += 4;
8927                         }
8928
8929                         if (sp != stack_start) {
8930                                 /* 
8931                                  * Link the current bb with the targets as well, so handle_stack_args
8932                                  * will set their in_stack correctly.
8933                                  */
8934                                 link_bblock (cfg, bblock, default_bblock);
8935                                 for (i = 0; i < n; ++i)
8936                                         link_bblock (cfg, bblock, targets [i]);
8937
8938                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8939                                 sp = stack_start;
8940                                 CHECK_UNVERIFIABLE (cfg);
8941                         }
8942
8943                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8944                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8945                         bblock = cfg->cbb;
8946
8947                         for (i = 0; i < n; ++i)
8948                                 link_bblock (cfg, bblock, targets [i]);
8949
8950                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8951                         table->table = targets;
8952                         table->table_size = n;
8953
8954                         use_op_switch = FALSE;
8955 #ifdef TARGET_ARM
8956                         /* ARM implements SWITCH statements differently */
8957                         /* FIXME: Make it use the generic implementation */
8958                         if (!cfg->compile_aot)
8959                                 use_op_switch = TRUE;
8960 #endif
8961
8962                         if (COMPILE_LLVM (cfg))
8963                                 use_op_switch = TRUE;
8964
8965                         cfg->cbb->has_jump_table = 1;
8966
8967                         if (use_op_switch) {
8968                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8969                                 ins->sreg1 = src1->dreg;
8970                                 ins->inst_p0 = table;
8971                                 ins->inst_many_bb = targets;
8972                                 ins->klass = GUINT_TO_POINTER (n);
8973                                 MONO_ADD_INS (cfg->cbb, ins);
8974                         } else {
8975                                 if (sizeof (gpointer) == 8)
8976                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8977                                 else
8978                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8979
8980 #if SIZEOF_REGISTER == 8
8981                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8982                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8983 #endif
8984
8985                                 if (cfg->compile_aot) {
8986                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8987                                 } else {
8988                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8989                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8990                                         ins->inst_p0 = table;
8991                                         ins->dreg = table_reg;
8992                                         MONO_ADD_INS (cfg->cbb, ins);
8993                                 }
8994
8995                                 /* FIXME: Use load_memindex */
8996                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8997                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8998                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8999                         }
9000                         start_new_bblock = 1;
9001                         inline_costs += (BRANCH_COST * 2);
9002                         break;
9003                 }
9004                 case CEE_LDIND_I1:
9005                 case CEE_LDIND_U1:
9006                 case CEE_LDIND_I2:
9007                 case CEE_LDIND_U2:
9008                 case CEE_LDIND_I4:
9009                 case CEE_LDIND_U4:
9010                 case CEE_LDIND_I8:
9011                 case CEE_LDIND_I:
9012                 case CEE_LDIND_R4:
9013                 case CEE_LDIND_R8:
9014                 case CEE_LDIND_REF:
9015                         CHECK_STACK (1);
9016                         --sp;
9017
9018                         switch (*ip) {
9019                         case CEE_LDIND_R4:
9020                         case CEE_LDIND_R8:
9021                                 dreg = alloc_freg (cfg);
9022                                 break;
9023                         case CEE_LDIND_I8:
9024                                 dreg = alloc_lreg (cfg);
9025                                 break;
9026                         case CEE_LDIND_REF:
9027                                 dreg = alloc_ireg_ref (cfg);
9028                                 break;
9029                         default:
9030                                 dreg = alloc_preg (cfg);
9031                         }
9032
9033                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9034                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9035                         ins->flags |= ins_flag;
9036                         MONO_ADD_INS (bblock, ins);
9037                         *sp++ = ins;
9038                         if (ins_flag & MONO_INST_VOLATILE) {
9039                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9040                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9041                                 emit_memory_barrier (cfg, FullBarrier);
9042                         }
9043                         ins_flag = 0;
9044                         ++ip;
9045                         break;
9046                 case CEE_STIND_REF:
9047                 case CEE_STIND_I1:
9048                 case CEE_STIND_I2:
9049                 case CEE_STIND_I4:
9050                 case CEE_STIND_I8:
9051                 case CEE_STIND_R4:
9052                 case CEE_STIND_R8:
9053                 case CEE_STIND_I:
9054                         CHECK_STACK (2);
9055                         sp -= 2;
9056
9057                         if (ins_flag & MONO_INST_VOLATILE) {
9058                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9059                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9060                                 emit_memory_barrier (cfg, FullBarrier);
9061                         }
9062
9063                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9064                         ins->flags |= ins_flag;
9065                         ins_flag = 0;
9066
9067                         MONO_ADD_INS (bblock, ins);
9068
9069                         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)))
9070                                 emit_write_barrier (cfg, sp [0], sp [1]);
9071
9072                         inline_costs += 1;
9073                         ++ip;
9074                         break;
9075
9076                 case CEE_MUL:
9077                         CHECK_STACK (2);
9078
9079                         MONO_INST_NEW (cfg, ins, (*ip));
9080                         sp -= 2;
9081                         ins->sreg1 = sp [0]->dreg;
9082                         ins->sreg2 = sp [1]->dreg;
9083                         type_from_op (ins, sp [0], sp [1]);
9084                         CHECK_TYPE (ins);
9085                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9086
9087                         /* Use the immediate opcodes if possible */
9088                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9089                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9090                                 if (imm_opcode != -1) {
9091                                         ins->opcode = imm_opcode;
9092                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9093                                         ins->sreg2 = -1;
9094
9095                                         sp [1]->opcode = OP_NOP;
9096                                 }
9097                         }
9098
9099                         MONO_ADD_INS ((cfg)->cbb, (ins));
9100
9101                         *sp++ = mono_decompose_opcode (cfg, ins);
9102                         ip++;
9103                         break;
9104                 case CEE_ADD:
9105                 case CEE_SUB:
9106                 case CEE_DIV:
9107                 case CEE_DIV_UN:
9108                 case CEE_REM:
9109                 case CEE_REM_UN:
9110                 case CEE_AND:
9111                 case CEE_OR:
9112                 case CEE_XOR:
9113                 case CEE_SHL:
9114                 case CEE_SHR:
9115                 case CEE_SHR_UN:
9116                         CHECK_STACK (2);
9117
9118                         MONO_INST_NEW (cfg, ins, (*ip));
9119                         sp -= 2;
9120                         ins->sreg1 = sp [0]->dreg;
9121                         ins->sreg2 = sp [1]->dreg;
9122                         type_from_op (ins, sp [0], sp [1]);
9123                         CHECK_TYPE (ins);
9124                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9125                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9126
9127                         /* FIXME: Pass opcode to is_inst_imm */
9128
9129                         /* Use the immediate opcodes if possible */
9130                         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)) {
9131                                 int imm_opcode;
9132
9133                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9134 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9135                                 /* Keep emulated opcodes which are optimized away later */
9136                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
9137                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9138                                 }
9139 #endif
9140                                 if (imm_opcode != -1) {
9141                                         ins->opcode = imm_opcode;
9142                                         if (sp [1]->opcode == OP_I8CONST) {
9143 #if SIZEOF_REGISTER == 8
9144                                                 ins->inst_imm = sp [1]->inst_l;
9145 #else
9146                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9147                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9148 #endif
9149                                         }
9150                                         else
9151                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9152                                         ins->sreg2 = -1;
9153
9154                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9155                                         if (sp [1]->next == NULL)
9156                                                 sp [1]->opcode = OP_NOP;
9157                                 }
9158                         }
9159                         MONO_ADD_INS ((cfg)->cbb, (ins));
9160
9161                         *sp++ = mono_decompose_opcode (cfg, ins);
9162                         ip++;
9163                         break;
9164                 case CEE_NEG:
9165                 case CEE_NOT:
9166                 case CEE_CONV_I1:
9167                 case CEE_CONV_I2:
9168                 case CEE_CONV_I4:
9169                 case CEE_CONV_R4:
9170                 case CEE_CONV_R8:
9171                 case CEE_CONV_U4:
9172                 case CEE_CONV_I8:
9173                 case CEE_CONV_U8:
9174                 case CEE_CONV_OVF_I8:
9175                 case CEE_CONV_OVF_U8:
9176                 case CEE_CONV_R_UN:
9177                         CHECK_STACK (1);
9178
9179                         /* Special case this earlier so we have long constants in the IR */
9180                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9181                                 int data = sp [-1]->inst_c0;
9182                                 sp [-1]->opcode = OP_I8CONST;
9183                                 sp [-1]->type = STACK_I8;
9184 #if SIZEOF_REGISTER == 8
9185                                 if ((*ip) == CEE_CONV_U8)
9186                                         sp [-1]->inst_c0 = (guint32)data;
9187                                 else
9188                                         sp [-1]->inst_c0 = data;
9189 #else
9190                                 sp [-1]->inst_ls_word = data;
9191                                 if ((*ip) == CEE_CONV_U8)
9192                                         sp [-1]->inst_ms_word = 0;
9193                                 else
9194                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9195 #endif
9196                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9197                         }
9198                         else {
9199                                 ADD_UNOP (*ip);
9200                         }
9201                         ip++;
9202                         break;
9203                 case CEE_CONV_OVF_I4:
9204                 case CEE_CONV_OVF_I1:
9205                 case CEE_CONV_OVF_I2:
9206                 case CEE_CONV_OVF_I:
9207                 case CEE_CONV_OVF_U:
9208                         CHECK_STACK (1);
9209
9210                         if (sp [-1]->type == STACK_R8) {
9211                                 ADD_UNOP (CEE_CONV_OVF_I8);
9212                                 ADD_UNOP (*ip);
9213                         } else {
9214                                 ADD_UNOP (*ip);
9215                         }
9216                         ip++;
9217                         break;
9218                 case CEE_CONV_OVF_U1:
9219                 case CEE_CONV_OVF_U2:
9220                 case CEE_CONV_OVF_U4:
9221                         CHECK_STACK (1);
9222
9223                         if (sp [-1]->type == STACK_R8) {
9224                                 ADD_UNOP (CEE_CONV_OVF_U8);
9225                                 ADD_UNOP (*ip);
9226                         } else {
9227                                 ADD_UNOP (*ip);
9228                         }
9229                         ip++;
9230                         break;
9231                 case CEE_CONV_OVF_I1_UN:
9232                 case CEE_CONV_OVF_I2_UN:
9233                 case CEE_CONV_OVF_I4_UN:
9234                 case CEE_CONV_OVF_I8_UN:
9235                 case CEE_CONV_OVF_U1_UN:
9236                 case CEE_CONV_OVF_U2_UN:
9237                 case CEE_CONV_OVF_U4_UN:
9238                 case CEE_CONV_OVF_U8_UN:
9239                 case CEE_CONV_OVF_I_UN:
9240                 case CEE_CONV_OVF_U_UN:
9241                 case CEE_CONV_U2:
9242                 case CEE_CONV_U1:
9243                 case CEE_CONV_I:
9244                 case CEE_CONV_U:
9245                         CHECK_STACK (1);
9246                         ADD_UNOP (*ip);
9247                         CHECK_CFG_EXCEPTION;
9248                         ip++;
9249                         break;
9250                 case CEE_ADD_OVF:
9251                 case CEE_ADD_OVF_UN:
9252                 case CEE_MUL_OVF:
9253                 case CEE_MUL_OVF_UN:
9254                 case CEE_SUB_OVF:
9255                 case CEE_SUB_OVF_UN:
9256                         CHECK_STACK (2);
9257                         ADD_BINOP (*ip);
9258                         ip++;
9259                         break;
9260                 case CEE_CPOBJ:
9261                         GSHAREDVT_FAILURE (*ip);
9262                         CHECK_OPSIZE (5);
9263                         CHECK_STACK (2);
9264                         token = read32 (ip + 1);
9265                         klass = mini_get_class (method, token, generic_context);
9266                         CHECK_TYPELOAD (klass);
9267                         sp -= 2;
9268                         if (generic_class_is_reference_type (cfg, klass)) {
9269                                 MonoInst *store, *load;
9270                                 int dreg = alloc_ireg_ref (cfg);
9271
9272                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9273                                 load->flags |= ins_flag;
9274                                 MONO_ADD_INS (cfg->cbb, load);
9275
9276                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9277                                 store->flags |= ins_flag;
9278                                 MONO_ADD_INS (cfg->cbb, store);
9279
9280                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9281                                         emit_write_barrier (cfg, sp [0], sp [1]);
9282                         } else {
9283                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9284                         }
9285                         ins_flag = 0;
9286                         ip += 5;
9287                         break;
9288                 case CEE_LDOBJ: {
9289                         int loc_index = -1;
9290                         int stloc_len = 0;
9291
9292                         CHECK_OPSIZE (5);
9293                         CHECK_STACK (1);
9294                         --sp;
9295                         token = read32 (ip + 1);
9296                         klass = mini_get_class (method, token, generic_context);
9297                         CHECK_TYPELOAD (klass);
9298
9299                         /* Optimize the common ldobj+stloc combination */
9300                         switch (ip [5]) {
9301                         case CEE_STLOC_S:
9302                                 loc_index = ip [6];
9303                                 stloc_len = 2;
9304                                 break;
9305                         case CEE_STLOC_0:
9306                         case CEE_STLOC_1:
9307                         case CEE_STLOC_2:
9308                         case CEE_STLOC_3:
9309                                 loc_index = ip [5] - CEE_STLOC_0;
9310                                 stloc_len = 1;
9311                                 break;
9312                         default:
9313                                 break;
9314                         }
9315
9316                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9317                                 CHECK_LOCAL (loc_index);
9318
9319                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9320                                 ins->dreg = cfg->locals [loc_index]->dreg;
9321                                 ins->flags |= ins_flag;
9322                                 ip += 5;
9323                                 ip += stloc_len;
9324                                 if (ins_flag & MONO_INST_VOLATILE) {
9325                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9326                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9327                                         emit_memory_barrier (cfg, FullBarrier);
9328                                 }
9329                                 ins_flag = 0;
9330                                 break;
9331                         }
9332
9333                         /* Optimize the ldobj+stobj combination */
9334                         /* The reference case ends up being a load+store anyway */
9335                         /* Skip this if the operation is volatile. */
9336                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
9337                                 CHECK_STACK (1);
9338
9339                                 sp --;
9340
9341                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9342
9343                                 ip += 5 + 5;
9344                                 ins_flag = 0;
9345                                 break;
9346                         }
9347
9348                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9349                         ins->flags |= ins_flag;
9350                         *sp++ = ins;
9351
9352                         if (ins_flag & MONO_INST_VOLATILE) {
9353                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9354                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9355                                 emit_memory_barrier (cfg, FullBarrier);
9356                         }
9357
9358                         ip += 5;
9359                         ins_flag = 0;
9360                         inline_costs += 1;
9361                         break;
9362                 }
9363                 case CEE_LDSTR:
9364                         CHECK_STACK_OVF (1);
9365                         CHECK_OPSIZE (5);
9366                         n = read32 (ip + 1);
9367
9368                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9369                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9370                                 ins->type = STACK_OBJ;
9371                                 *sp = ins;
9372                         }
9373                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9374                                 MonoInst *iargs [1];
9375
9376                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9377                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9378                         } else {
9379                                 if (cfg->opt & MONO_OPT_SHARED) {
9380                                         MonoInst *iargs [3];
9381
9382                                         if (cfg->compile_aot) {
9383                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9384                                         }
9385                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9386                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9387                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9388                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9389                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9390                                 } else {
9391                                         if (bblock->out_of_line) {
9392                                                 MonoInst *iargs [2];
9393
9394                                                 if (image == mono_defaults.corlib) {
9395                                                         /* 
9396                                                          * Avoid relocations in AOT and save some space by using a 
9397                                                          * version of helper_ldstr specialized to mscorlib.
9398                                                          */
9399                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9400                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9401                                                 } else {
9402                                                         /* Avoid creating the string object */
9403                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9404                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9405                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9406                                                 }
9407                                         } 
9408                                         else
9409                                         if (cfg->compile_aot) {
9410                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9411                                                 *sp = ins;
9412                                                 MONO_ADD_INS (bblock, ins);
9413                                         } 
9414                                         else {
9415                                                 NEW_PCONST (cfg, ins, NULL);
9416                                                 ins->type = STACK_OBJ;
9417                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9418                                                 if (!ins->inst_p0)
9419                                                         OUT_OF_MEMORY_FAILURE;
9420
9421                                                 *sp = ins;
9422                                                 MONO_ADD_INS (bblock, ins);
9423                                         }
9424                                 }
9425                         }
9426
9427                         sp++;
9428                         ip += 5;
9429                         break;
9430                 case CEE_NEWOBJ: {
9431                         MonoInst *iargs [2];
9432                         MonoMethodSignature *fsig;
9433                         MonoInst this_ins;
9434                         MonoInst *alloc;
9435                         MonoInst *vtable_arg = NULL;
9436
9437                         CHECK_OPSIZE (5);
9438                         token = read32 (ip + 1);
9439                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9440                         if (!cmethod || mono_loader_get_last_error ())
9441                                 LOAD_ERROR;
9442                         fsig = mono_method_get_signature (cmethod, image, token);
9443                         if (!fsig)
9444                                 LOAD_ERROR;
9445
9446                         mono_save_token_info (cfg, image, token, cmethod);
9447
9448                         if (!mono_class_init (cmethod->klass))
9449                                 TYPE_LOAD_ERROR (cmethod->klass);
9450
9451                         context_used = mini_method_check_context_used (cfg, cmethod);
9452
9453                         if (mono_security_cas_enabled ()) {
9454                                 if (check_linkdemand (cfg, method, cmethod))
9455                                         INLINE_FAILURE ("linkdemand");
9456                                 CHECK_CFG_EXCEPTION;
9457                         } else if (mono_security_core_clr_enabled ()) {
9458                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9459                         }
9460
9461                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9462                                 emit_generic_class_init (cfg, cmethod->klass);
9463                                 CHECK_TYPELOAD (cmethod->klass);
9464                         }
9465
9466                         /*
9467                         if (cfg->gsharedvt) {
9468                                 if (mini_is_gsharedvt_variable_signature (sig))
9469                                         GSHAREDVT_FAILURE (*ip);
9470                         }
9471                         */
9472
9473                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9474                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9475                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9476                                         mono_class_vtable (cfg->domain, cmethod->klass);
9477                                         CHECK_TYPELOAD (cmethod->klass);
9478
9479                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9480                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9481                                 } else {
9482                                         if (context_used) {
9483                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9484                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9485                                         } else {
9486                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9487
9488                                                 CHECK_TYPELOAD (cmethod->klass);
9489                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9490                                         }
9491                                 }
9492                         }
9493
9494                         n = fsig->param_count;
9495                         CHECK_STACK (n);
9496
9497                         /* 
9498                          * Generate smaller code for the common newobj <exception> instruction in
9499                          * argument checking code.
9500                          */
9501                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9502                                 is_exception_class (cmethod->klass) && n <= 2 &&
9503                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9504                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9505                                 MonoInst *iargs [3];
9506
9507                                 g_assert (!vtable_arg);
9508
9509                                 sp -= n;
9510
9511                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9512                                 switch (n) {
9513                                 case 0:
9514                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9515                                         break;
9516                                 case 1:
9517                                         iargs [1] = sp [0];
9518                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9519                                         break;
9520                                 case 2:
9521                                         iargs [1] = sp [0];
9522                                         iargs [2] = sp [1];
9523                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9524                                         break;
9525                                 default:
9526                                         g_assert_not_reached ();
9527                                 }
9528
9529                                 ip += 5;
9530                                 inline_costs += 5;
9531                                 break;
9532                         }
9533
9534                         /* move the args to allow room for 'this' in the first position */
9535                         while (n--) {
9536                                 --sp;
9537                                 sp [1] = sp [0];
9538                         }
9539
9540                         /* check_call_signature () requires sp[0] to be set */
9541                         this_ins.type = STACK_OBJ;
9542                         sp [0] = &this_ins;
9543                         if (check_call_signature (cfg, fsig, sp))
9544                                 UNVERIFIED;
9545
9546                         iargs [0] = NULL;
9547
9548                         if (mini_class_is_system_array (cmethod->klass)) {
9549                                 g_assert (!vtable_arg);
9550
9551                                 *sp = emit_get_rgctx_method (cfg, context_used,
9552                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9553
9554                                 /* Avoid varargs in the common case */
9555                                 if (fsig->param_count == 1)
9556                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9557                                 else if (fsig->param_count == 2)
9558                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9559                                 else if (fsig->param_count == 3)
9560                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9561                                 else if (fsig->param_count == 4)
9562                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9563                                 else
9564                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9565                         } else if (cmethod->string_ctor) {
9566                                 g_assert (!context_used);
9567                                 g_assert (!vtable_arg);
9568                                 /* we simply pass a null pointer */
9569                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9570                                 /* now call the string ctor */
9571                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9572                         } else {
9573                                 MonoInst* callvirt_this_arg = NULL;
9574                                 
9575                                 if (cmethod->klass->valuetype) {
9576                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9577                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9578                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9579
9580                                         alloc = NULL;
9581
9582                                         /* 
9583                                          * The code generated by mini_emit_virtual_call () expects
9584                                          * iargs [0] to be a boxed instance, but luckily the vcall
9585                                          * will be transformed into a normal call there.
9586                                          */
9587                                 } else if (context_used) {
9588                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9589                                         *sp = alloc;
9590                                 } else {
9591                                         MonoVTable *vtable = NULL;
9592
9593                                         if (!cfg->compile_aot)
9594                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9595                                         CHECK_TYPELOAD (cmethod->klass);
9596
9597                                         /*
9598                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9599                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9600                                          * As a workaround, we call class cctors before allocating objects.
9601                                          */
9602                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9603                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9604                                                 if (cfg->verbose_level > 2)
9605                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9606                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9607                                         }
9608
9609                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9610                                         *sp = alloc;
9611                                 }
9612                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9613
9614                                 if (alloc)
9615                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9616
9617                                 /* Now call the actual ctor */
9618                                 /* Avoid virtual calls to ctors if possible */
9619                                 if (mono_class_is_marshalbyref (cmethod->klass))
9620                                         callvirt_this_arg = sp [0];
9621
9622
9623                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9624                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9625                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9626                                                 *sp = ins;
9627                                                 sp++;
9628                                         }
9629
9630                                         CHECK_CFG_EXCEPTION;
9631                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9632                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9633                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9634                                     !g_list_find (dont_inline, cmethod)) {
9635                                         int costs;
9636
9637                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9638                                                 cfg->real_offset += 5;
9639                                                 bblock = cfg->cbb;
9640
9641                                                 inline_costs += costs - 5;
9642                                         } else {
9643                                                 INLINE_FAILURE ("inline failure");
9644                                                 // FIXME-VT: Clean this up
9645                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9646                                                         GSHAREDVT_FAILURE(*ip);
9647                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9648                                         }
9649                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9650                                         MonoInst *addr;
9651
9652                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9653                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9654                                 } else if (context_used &&
9655                                                    ((!mono_method_is_generic_sharable (cmethod, TRUE) ||
9656                                                          !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
9657                                         MonoInst *cmethod_addr;
9658
9659                                         /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
9660
9661                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9662                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9663
9664                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9665                                 } else {
9666                                         INLINE_FAILURE ("ctor call");
9667                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9668                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9669                                 }
9670                         }
9671
9672                         if (alloc == NULL) {
9673                                 /* Valuetype */
9674                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9675                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9676                                 *sp++= ins;
9677                         }
9678                         else
9679                                 *sp++ = alloc;
9680                         
9681                         ip += 5;
9682                         inline_costs += 5;
9683                         break;
9684                 }
9685                 case CEE_CASTCLASS:
9686                         CHECK_STACK (1);
9687                         --sp;
9688                         CHECK_OPSIZE (5);
9689                         token = read32 (ip + 1);
9690                         klass = mini_get_class (method, token, generic_context);
9691                         CHECK_TYPELOAD (klass);
9692                         if (sp [0]->type != STACK_OBJ)
9693                                 UNVERIFIED;
9694
9695                         context_used = mini_class_check_context_used (cfg, klass);
9696
9697                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9698                                 MonoInst *args [3];
9699
9700                                 /* obj */
9701                                 args [0] = *sp;
9702
9703                                 /* klass */
9704                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9705
9706                                 /* inline cache*/
9707                                 if (cfg->compile_aot)
9708                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9709                                 else
9710                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9711
9712                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9713
9714                                 *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9715                                 ip += 5;
9716                                 inline_costs += 2;
9717                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9718                                 MonoMethod *mono_castclass;
9719                                 MonoInst *iargs [1];
9720                                 int costs;
9721
9722                                 mono_castclass = mono_marshal_get_castclass (klass); 
9723                                 iargs [0] = sp [0];
9724                                 
9725                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9726                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9727                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9728                                 reset_cast_details (cfg);
9729                                 CHECK_CFG_EXCEPTION;
9730                                 g_assert (costs > 0);
9731                                 
9732                                 ip += 5;
9733                                 cfg->real_offset += 5;
9734                                 bblock = cfg->cbb;
9735
9736                                 *sp++ = iargs [0];
9737
9738                                 inline_costs += costs;
9739                         }
9740                         else {
9741                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9742                                 CHECK_CFG_EXCEPTION;
9743                                 bblock = cfg->cbb;
9744                                 *sp ++ = ins;
9745                                 ip += 5;
9746                         }
9747                         break;
9748                 case CEE_ISINST: {
9749                         CHECK_STACK (1);
9750                         --sp;
9751                         CHECK_OPSIZE (5);
9752                         token = read32 (ip + 1);
9753                         klass = mini_get_class (method, token, generic_context);
9754                         CHECK_TYPELOAD (klass);
9755                         if (sp [0]->type != STACK_OBJ)
9756                                 UNVERIFIED;
9757  
9758                         context_used = mini_class_check_context_used (cfg, klass);
9759
9760                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9761                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9762                                 MonoInst *args [3];
9763
9764                                 /* obj */
9765                                 args [0] = *sp;
9766
9767                                 /* klass */
9768                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9769
9770                                 /* inline cache*/
9771                                 if (cfg->compile_aot)
9772                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9773                                 else
9774                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9775
9776                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9777                                 ip += 5;
9778                                 inline_costs += 2;
9779                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9780                                 MonoMethod *mono_isinst;
9781                                 MonoInst *iargs [1];
9782                                 int costs;
9783
9784                                 mono_isinst = mono_marshal_get_isinst (klass); 
9785                                 iargs [0] = sp [0];
9786
9787                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9788                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9789                                 CHECK_CFG_EXCEPTION;
9790                                 g_assert (costs > 0);
9791                                 
9792                                 ip += 5;
9793                                 cfg->real_offset += 5;
9794                                 bblock = cfg->cbb;
9795
9796                                 *sp++= iargs [0];
9797
9798                                 inline_costs += costs;
9799                         }
9800                         else {
9801                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9802                                 CHECK_CFG_EXCEPTION;
9803                                 bblock = cfg->cbb;
9804                                 *sp ++ = ins;
9805                                 ip += 5;
9806                         }
9807                         break;
9808                 }
9809                 case CEE_UNBOX_ANY: {
9810                         CHECK_STACK (1);
9811                         --sp;
9812                         CHECK_OPSIZE (5);
9813                         token = read32 (ip + 1);
9814                         klass = mini_get_class (method, token, generic_context);
9815                         CHECK_TYPELOAD (klass);
9816  
9817                         mono_save_token_info (cfg, image, token, klass);
9818
9819                         context_used = mini_class_check_context_used (cfg, klass);
9820
9821                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9822                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9823                                 sp ++;
9824
9825                                 ip += 5;
9826                                 inline_costs += 2;
9827                                 break;
9828                         }
9829
9830                         if (generic_class_is_reference_type (cfg, klass)) {
9831                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9832                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9833                                         MonoInst *args [3];
9834
9835                                         /* obj */
9836                                         args [0] = *sp;
9837
9838                                         /* klass */
9839                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9840
9841                                         /* inline cache*/
9842                                         /*FIXME AOT support*/
9843                                         if (cfg->compile_aot)
9844                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9845                                         else
9846                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9847
9848                                         /* The wrapper doesn't inline well so the bloat of inlining doesn't pay off. */
9849                                         *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9850                                         ip += 5;
9851                                         inline_costs += 2;
9852                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9853                                         MonoMethod *mono_castclass;
9854                                         MonoInst *iargs [1];
9855                                         int costs;
9856
9857                                         mono_castclass = mono_marshal_get_castclass (klass); 
9858                                         iargs [0] = sp [0];
9859
9860                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9861                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9862                                         CHECK_CFG_EXCEPTION;
9863                                         g_assert (costs > 0);
9864                                 
9865                                         ip += 5;
9866                                         cfg->real_offset += 5;
9867                                         bblock = cfg->cbb;
9868
9869                                         *sp++ = iargs [0];
9870                                         inline_costs += costs;
9871                                 } else {
9872                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9873                                         CHECK_CFG_EXCEPTION;
9874                                         bblock = cfg->cbb;
9875                                         *sp ++ = ins;
9876                                         ip += 5;
9877                                 }
9878                                 break;
9879                         }
9880
9881                         if (mono_class_is_nullable (klass)) {
9882                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9883                                 *sp++= ins;
9884                                 ip += 5;
9885                                 break;
9886                         }
9887
9888                         /* UNBOX */
9889                         ins = handle_unbox (cfg, klass, sp, context_used);
9890                         *sp = ins;
9891
9892                         ip += 5;
9893
9894                         /* LDOBJ */
9895                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9896                         *sp++ = ins;
9897
9898                         inline_costs += 2;
9899                         break;
9900                 }
9901                 case CEE_BOX: {
9902                         MonoInst *val;
9903
9904                         CHECK_STACK (1);
9905                         --sp;
9906                         val = *sp;
9907                         CHECK_OPSIZE (5);
9908                         token = read32 (ip + 1);
9909                         klass = mini_get_class (method, token, generic_context);
9910                         CHECK_TYPELOAD (klass);
9911
9912                         mono_save_token_info (cfg, image, token, klass);
9913
9914                         context_used = mini_class_check_context_used (cfg, klass);
9915
9916                         if (generic_class_is_reference_type (cfg, klass)) {
9917                                 *sp++ = val;
9918                                 ip += 5;
9919                                 break;
9920                         }
9921
9922                         if (klass == mono_defaults.void_class)
9923                                 UNVERIFIED;
9924                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9925                                 UNVERIFIED;
9926                         /* frequent check in generic code: box (struct), brtrue */
9927
9928                         // FIXME: LLVM can't handle the inconsistent bb linking
9929                         if (!mono_class_is_nullable (klass) &&
9930                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9931                                 (ip [5] == CEE_BRTRUE || 
9932                                  ip [5] == CEE_BRTRUE_S ||
9933                                  ip [5] == CEE_BRFALSE ||
9934                                  ip [5] == CEE_BRFALSE_S)) {
9935                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9936                                 int dreg;
9937                                 MonoBasicBlock *true_bb, *false_bb;
9938
9939                                 ip += 5;
9940
9941                                 if (cfg->verbose_level > 3) {
9942                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9943                                         printf ("<box+brtrue opt>\n");
9944                                 }
9945
9946                                 switch (*ip) {
9947                                 case CEE_BRTRUE_S:
9948                                 case CEE_BRFALSE_S:
9949                                         CHECK_OPSIZE (2);
9950                                         ip++;
9951                                         target = ip + 1 + (signed char)(*ip);
9952                                         ip++;
9953                                         break;
9954                                 case CEE_BRTRUE:
9955                                 case CEE_BRFALSE:
9956                                         CHECK_OPSIZE (5);
9957                                         ip++;
9958                                         target = ip + 4 + (gint)(read32 (ip));
9959                                         ip += 4;
9960                                         break;
9961                                 default:
9962                                         g_assert_not_reached ();
9963                                 }
9964
9965                                 /* 
9966                                  * We need to link both bblocks, since it is needed for handling stack
9967                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9968                                  * Branching to only one of them would lead to inconsistencies, so
9969                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9970                                  */
9971                                 GET_BBLOCK (cfg, true_bb, target);
9972                                 GET_BBLOCK (cfg, false_bb, ip);
9973
9974                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9975                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9976
9977                                 if (sp != stack_start) {
9978                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9979                                         sp = stack_start;
9980                                         CHECK_UNVERIFIABLE (cfg);
9981                                 }
9982
9983                                 if (COMPILE_LLVM (cfg)) {
9984                                         dreg = alloc_ireg (cfg);
9985                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9986                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9987
9988                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9989                                 } else {
9990                                         /* The JIT can't eliminate the iconst+compare */
9991                                         MONO_INST_NEW (cfg, ins, OP_BR);
9992                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9993                                         MONO_ADD_INS (cfg->cbb, ins);
9994                                 }
9995
9996                                 start_new_bblock = 1;
9997                                 break;
9998                         }
9999
10000                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10001
10002                         CHECK_CFG_EXCEPTION;
10003                         ip += 5;
10004                         inline_costs += 1;
10005                         break;
10006                 }
10007                 case CEE_UNBOX: {
10008                         CHECK_STACK (1);
10009                         --sp;
10010                         CHECK_OPSIZE (5);
10011                         token = read32 (ip + 1);
10012                         klass = mini_get_class (method, token, generic_context);
10013                         CHECK_TYPELOAD (klass);
10014
10015                         mono_save_token_info (cfg, image, token, klass);
10016
10017                         context_used = mini_class_check_context_used (cfg, klass);
10018
10019                         if (mono_class_is_nullable (klass)) {
10020                                 MonoInst *val;
10021
10022                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10023                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10024
10025                                 *sp++= ins;
10026                         } else {
10027                                 ins = handle_unbox (cfg, klass, sp, context_used);
10028                                 *sp++ = ins;
10029                         }
10030                         ip += 5;
10031                         inline_costs += 2;
10032                         break;
10033                 }
10034                 case CEE_LDFLD:
10035                 case CEE_LDFLDA:
10036                 case CEE_STFLD:
10037                 case CEE_LDSFLD:
10038                 case CEE_LDSFLDA:
10039                 case CEE_STSFLD: {
10040                         MonoClassField *field;
10041 #ifndef DISABLE_REMOTING
10042                         int costs;
10043 #endif
10044                         guint foffset;
10045                         gboolean is_instance;
10046                         int op;
10047                         gpointer addr = NULL;
10048                         gboolean is_special_static;
10049                         MonoType *ftype;
10050                         MonoInst *store_val = NULL;
10051                         MonoInst *thread_ins;
10052
10053                         op = *ip;
10054                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10055                         if (is_instance) {
10056                                 if (op == CEE_STFLD) {
10057                                         CHECK_STACK (2);
10058                                         sp -= 2;
10059                                         store_val = sp [1];
10060                                 } else {
10061                                         CHECK_STACK (1);
10062                                         --sp;
10063                                 }
10064                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10065                                         UNVERIFIED;
10066                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10067                                         UNVERIFIED;
10068                         } else {
10069                                 if (op == CEE_STSFLD) {
10070                                         CHECK_STACK (1);
10071                                         sp--;
10072                                         store_val = sp [0];
10073                                 }
10074                         }
10075
10076                         CHECK_OPSIZE (5);
10077                         token = read32 (ip + 1);
10078                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10079                                 field = mono_method_get_wrapper_data (method, token);
10080                                 klass = field->parent;
10081                         }
10082                         else {
10083                                 field = mono_field_from_token (image, token, &klass, generic_context);
10084                         }
10085                         if (!field)
10086                                 LOAD_ERROR;
10087                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10088                                 FIELD_ACCESS_FAILURE;
10089                         mono_class_init (klass);
10090
10091                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10092                                 UNVERIFIED;
10093
10094                         /* if the class is Critical then transparent code cannot access it's fields */
10095                         if (!is_instance && mono_security_core_clr_enabled ())
10096                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10097
10098                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10099                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10100                         if (mono_security_core_clr_enabled ())
10101                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10102                         */
10103
10104                         /*
10105                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10106                          * the static case.
10107                          */
10108                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10109                                 switch (op) {
10110                                 case CEE_LDFLD:
10111                                         op = CEE_LDSFLD;
10112                                         break;
10113                                 case CEE_STFLD:
10114                                         op = CEE_STSFLD;
10115                                         break;
10116                                 case CEE_LDFLDA:
10117                                         op = CEE_LDSFLDA;
10118                                         break;
10119                                 default:
10120                                         g_assert_not_reached ();
10121                                 }
10122                                 is_instance = FALSE;
10123                         }
10124
10125                         context_used = mini_class_check_context_used (cfg, klass);
10126
10127                         /* INSTANCE CASE */
10128
10129                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10130                         if (op == CEE_STFLD) {
10131                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10132                                         UNVERIFIED;
10133 #ifndef DISABLE_REMOTING
10134                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10135                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10136                                         MonoInst *iargs [5];
10137
10138                                         GSHAREDVT_FAILURE (op);
10139
10140                                         iargs [0] = sp [0];
10141                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10142                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10143                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10144                                                     field->offset);
10145                                         iargs [4] = sp [1];
10146
10147                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10148                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10149                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
10150                                                 CHECK_CFG_EXCEPTION;
10151                                                 g_assert (costs > 0);
10152                                                       
10153                                                 cfg->real_offset += 5;
10154                                                 bblock = cfg->cbb;
10155
10156                                                 inline_costs += costs;
10157                                         } else {
10158                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10159                                         }
10160                                 } else
10161 #endif
10162                                 {
10163                                         MonoInst *store;
10164
10165                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10166
10167                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10168                                                 MonoInst *offset_ins;
10169
10170                                                 context_used = mini_class_check_context_used (cfg, klass);
10171
10172                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10173                                                 dreg = alloc_ireg_mp (cfg);
10174                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10175                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10176                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10177                                         } else {
10178                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10179                                         }
10180                                         if (sp [0]->opcode != OP_LDADDR)
10181                                                 store->flags |= MONO_INST_FAULT;
10182
10183                                 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)) {
10184                                         /* insert call to write barrier */
10185                                         MonoInst *ptr;
10186                                         int dreg;
10187
10188                                         dreg = alloc_ireg_mp (cfg);
10189                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10190                                         emit_write_barrier (cfg, ptr, sp [1]);
10191                                 }
10192
10193                                         store->flags |= ins_flag;
10194                                 }
10195                                 ins_flag = 0;
10196                                 ip += 5;
10197                                 break;
10198                         }
10199
10200 #ifndef DISABLE_REMOTING
10201                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10202                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10203                                 MonoInst *iargs [4];
10204
10205                                 GSHAREDVT_FAILURE (op);
10206
10207                                 iargs [0] = sp [0];
10208                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10209                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10210                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10211                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10212                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10213                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
10214                                         CHECK_CFG_EXCEPTION;
10215                                         bblock = cfg->cbb;
10216                                         g_assert (costs > 0);
10217                                                       
10218                                         cfg->real_offset += 5;
10219
10220                                         *sp++ = iargs [0];
10221
10222                                         inline_costs += costs;
10223                                 } else {
10224                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10225                                         *sp++ = ins;
10226                                 }
10227                         } else 
10228 #endif
10229                         if (is_instance) {
10230                                 if (sp [0]->type == STACK_VTYPE) {
10231                                         MonoInst *var;
10232
10233                                         /* Have to compute the address of the variable */
10234
10235                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10236                                         if (!var)
10237                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10238                                         else
10239                                                 g_assert (var->klass == klass);
10240                                         
10241                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10242                                         sp [0] = ins;
10243                                 }
10244
10245                                 if (op == CEE_LDFLDA) {
10246                                         if (is_magic_tls_access (field)) {
10247                                                 GSHAREDVT_FAILURE (*ip);
10248                                                 ins = sp [0];
10249                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10250                                         } else {
10251                                                 if (sp [0]->type == STACK_OBJ) {
10252                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10253                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10254                                                 }
10255
10256                                                 dreg = alloc_ireg_mp (cfg);
10257
10258                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10259                                                         MonoInst *offset_ins;
10260
10261                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10262                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10263                                                 } else {
10264                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10265                                                 }
10266                                                 ins->klass = mono_class_from_mono_type (field->type);
10267                                                 ins->type = STACK_MP;
10268                                                 *sp++ = ins;
10269                                         }
10270                                 } else {
10271                                         MonoInst *load;
10272
10273                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10274
10275                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10276                                                 MonoInst *offset_ins;
10277
10278                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10279                                                 dreg = alloc_ireg_mp (cfg);
10280                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10281                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10282                                         } else {
10283                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10284                                         }
10285                                         load->flags |= ins_flag;
10286                                         if (sp [0]->opcode != OP_LDADDR)
10287                                                 load->flags |= MONO_INST_FAULT;
10288                                         *sp++ = load;
10289                                 }
10290                         }
10291
10292                         if (is_instance) {
10293                                 ins_flag = 0;
10294                                 ip += 5;
10295                                 break;
10296                         }
10297
10298                         /* STATIC CASE */
10299
10300                         /*
10301                          * We can only support shared generic static
10302                          * field access on architectures where the
10303                          * trampoline code has been extended to handle
10304                          * the generic class init.
10305                          */
10306 #ifndef MONO_ARCH_VTABLE_REG
10307                         GENERIC_SHARING_FAILURE (op);
10308 #endif
10309
10310                         context_used = mini_class_check_context_used (cfg, klass);
10311
10312                         ftype = mono_field_get_type (field);
10313
10314                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10315                                 UNVERIFIED;
10316
10317                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10318                          * to be called here.
10319                          */
10320                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10321                                 mono_class_vtable (cfg->domain, klass);
10322                                 CHECK_TYPELOAD (klass);
10323                         }
10324                         mono_domain_lock (cfg->domain);
10325                         if (cfg->domain->special_static_fields)
10326                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10327                         mono_domain_unlock (cfg->domain);
10328
10329                         is_special_static = mono_class_field_is_special_static (field);
10330
10331                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10332                                 thread_ins = mono_get_thread_intrinsic (cfg);
10333                         else
10334                                 thread_ins = NULL;
10335
10336                         /* Generate IR to compute the field address */
10337                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10338                                 /*
10339                                  * Fast access to TLS data
10340                                  * Inline version of get_thread_static_data () in
10341                                  * threads.c.
10342                                  */
10343                                 guint32 offset;
10344                                 int idx, static_data_reg, array_reg, dreg;
10345
10346                                 GSHAREDVT_FAILURE (op);
10347
10348                                 // offset &= 0x7fffffff;
10349                                 // idx = (offset >> 24) - 1;
10350                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10351                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10352                                 static_data_reg = alloc_ireg (cfg);
10353                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10354
10355                                 if (cfg->compile_aot) {
10356                                         int offset_reg, offset2_reg, idx_reg;
10357
10358                                         /* For TLS variables, this will return the TLS offset */
10359                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10360                                         offset_reg = ins->dreg;
10361                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10362                                         idx_reg = alloc_ireg (cfg);
10363                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10364                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10365                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10366                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10367                                         array_reg = alloc_ireg (cfg);
10368                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10369                                         offset2_reg = alloc_ireg (cfg);
10370                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10371                                         dreg = alloc_ireg (cfg);
10372                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10373                                 } else {
10374                                         offset = (gsize)addr & 0x7fffffff;
10375                                         idx = (offset >> 24) - 1;
10376
10377                                         array_reg = alloc_ireg (cfg);
10378                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10379                                         dreg = alloc_ireg (cfg);
10380                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10381                                 }
10382                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10383                                         (cfg->compile_aot && is_special_static) ||
10384                                         (context_used && is_special_static)) {
10385                                 MonoInst *iargs [2];
10386
10387                                 g_assert (field->parent);
10388                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10389                                 if (context_used) {
10390                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10391                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10392                                 } else {
10393                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10394                                 }
10395                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10396                         } else if (context_used) {
10397                                 MonoInst *static_data;
10398
10399                                 /*
10400                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10401                                         method->klass->name_space, method->klass->name, method->name,
10402                                         depth, field->offset);
10403                                 */
10404
10405                                 if (mono_class_needs_cctor_run (klass, method))
10406                                         emit_generic_class_init (cfg, klass);
10407
10408                                 /*
10409                                  * The pointer we're computing here is
10410                                  *
10411                                  *   super_info.static_data + field->offset
10412                                  */
10413                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10414                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10415
10416                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10417                                         MonoInst *offset_ins;
10418
10419                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10420                                         dreg = alloc_ireg_mp (cfg);
10421                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10422                                 } else if (field->offset == 0) {
10423                                         ins = static_data;
10424                                 } else {
10425                                         int addr_reg = mono_alloc_preg (cfg);
10426                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10427                                 }
10428                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10429                                 MonoInst *iargs [2];
10430
10431                                 g_assert (field->parent);
10432                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10433                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10434                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10435                         } else {
10436                                 MonoVTable *vtable = NULL;
10437
10438                                 if (!cfg->compile_aot)
10439                                         vtable = mono_class_vtable (cfg->domain, klass);
10440                                 CHECK_TYPELOAD (klass);
10441
10442                                 if (!addr) {
10443                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10444                                                 if (!(g_slist_find (class_inits, klass))) {
10445                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10446                                                         if (cfg->verbose_level > 2)
10447                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10448                                                         class_inits = g_slist_prepend (class_inits, klass);
10449                                                 }
10450                                         } else {
10451                                                 if (cfg->run_cctors) {
10452                                                         MonoException *ex;
10453                                                         /* This makes so that inline cannot trigger */
10454                                                         /* .cctors: too many apps depend on them */
10455                                                         /* running with a specific order... */
10456                                                         g_assert (vtable);
10457                                                         if (! vtable->initialized)
10458                                                                 INLINE_FAILURE ("class init");
10459                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10460                                                         if (ex) {
10461                                                                 set_exception_object (cfg, ex);
10462                                                                 goto exception_exit;
10463                                                         }
10464                                                 }
10465                                         }
10466                                         if (cfg->compile_aot)
10467                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10468                                         else {
10469                                                 g_assert (vtable);
10470                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10471                                                 g_assert (addr);
10472                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10473                                         }
10474                                 } else {
10475                                         MonoInst *iargs [1];
10476                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10477                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10478                                 }
10479                         }
10480
10481                         /* Generate IR to do the actual load/store operation */
10482
10483                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10484                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10485                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10486                                 emit_memory_barrier (cfg, FullBarrier);
10487                         }
10488
10489                         if (op == CEE_LDSFLDA) {
10490                                 ins->klass = mono_class_from_mono_type (ftype);
10491                                 ins->type = STACK_PTR;
10492                                 *sp++ = ins;
10493                         } else if (op == CEE_STSFLD) {
10494                                 MonoInst *store;
10495
10496                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10497                                 store->flags |= ins_flag;
10498                         } else {
10499                                 gboolean is_const = FALSE;
10500                                 MonoVTable *vtable = NULL;
10501                                 gpointer addr = NULL;
10502
10503                                 if (!context_used) {
10504                                         vtable = mono_class_vtable (cfg->domain, klass);
10505                                         CHECK_TYPELOAD (klass);
10506                                 }
10507                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10508                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10509                                         int ro_type = ftype->type;
10510                                         if (!addr)
10511                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10512                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10513                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10514                                         }
10515
10516                                         GSHAREDVT_FAILURE (op);
10517
10518                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10519                                         is_const = TRUE;
10520                                         switch (ro_type) {
10521                                         case MONO_TYPE_BOOLEAN:
10522                                         case MONO_TYPE_U1:
10523                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10524                                                 sp++;
10525                                                 break;
10526                                         case MONO_TYPE_I1:
10527                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10528                                                 sp++;
10529                                                 break;                                          
10530                                         case MONO_TYPE_CHAR:
10531                                         case MONO_TYPE_U2:
10532                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10533                                                 sp++;
10534                                                 break;
10535                                         case MONO_TYPE_I2:
10536                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10537                                                 sp++;
10538                                                 break;
10539                                                 break;
10540                                         case MONO_TYPE_I4:
10541                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10542                                                 sp++;
10543                                                 break;                                          
10544                                         case MONO_TYPE_U4:
10545                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10546                                                 sp++;
10547                                                 break;
10548                                         case MONO_TYPE_I:
10549                                         case MONO_TYPE_U:
10550                                         case MONO_TYPE_PTR:
10551                                         case MONO_TYPE_FNPTR:
10552                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10553                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10554                                                 sp++;
10555                                                 break;
10556                                         case MONO_TYPE_STRING:
10557                                         case MONO_TYPE_OBJECT:
10558                                         case MONO_TYPE_CLASS:
10559                                         case MONO_TYPE_SZARRAY:
10560                                         case MONO_TYPE_ARRAY:
10561                                                 if (!mono_gc_is_moving ()) {
10562                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10563                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10564                                                         sp++;
10565                                                 } else {
10566                                                         is_const = FALSE;
10567                                                 }
10568                                                 break;
10569                                         case MONO_TYPE_I8:
10570                                         case MONO_TYPE_U8:
10571                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10572                                                 sp++;
10573                                                 break;
10574                                         case MONO_TYPE_R4:
10575                                         case MONO_TYPE_R8:
10576                                         case MONO_TYPE_VALUETYPE:
10577                                         default:
10578                                                 is_const = FALSE;
10579                                                 break;
10580                                         }
10581                                 }
10582
10583                                 if (!is_const) {
10584                                         MonoInst *load;
10585
10586                                         CHECK_STACK_OVF (1);
10587
10588                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10589                                         load->flags |= ins_flag;
10590                                         ins_flag = 0;
10591                                         *sp++ = load;
10592                                 }
10593                         }
10594
10595                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10596                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10597                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10598                                 emit_memory_barrier (cfg, FullBarrier);
10599                         }
10600
10601                         ins_flag = 0;
10602                         ip += 5;
10603                         break;
10604                 }
10605                 case CEE_STOBJ:
10606                         CHECK_STACK (2);
10607                         sp -= 2;
10608                         CHECK_OPSIZE (5);
10609                         token = read32 (ip + 1);
10610                         klass = mini_get_class (method, token, generic_context);
10611                         CHECK_TYPELOAD (klass);
10612                         if (ins_flag & MONO_INST_VOLATILE) {
10613                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10614                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10615                                 emit_memory_barrier (cfg, FullBarrier);
10616                         }
10617                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10618                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10619                         ins->flags |= ins_flag;
10620                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10621                                         generic_class_is_reference_type (cfg, klass)) {
10622                                 /* insert call to write barrier */
10623                                 emit_write_barrier (cfg, sp [0], sp [1]);
10624                         }
10625                         ins_flag = 0;
10626                         ip += 5;
10627                         inline_costs += 1;
10628                         break;
10629
10630                         /*
10631                          * Array opcodes
10632                          */
10633                 case CEE_NEWARR: {
10634                         MonoInst *len_ins;
10635                         const char *data_ptr;
10636                         int data_size = 0;
10637                         guint32 field_token;
10638
10639                         CHECK_STACK (1);
10640                         --sp;
10641
10642                         CHECK_OPSIZE (5);
10643                         token = read32 (ip + 1);
10644
10645                         klass = mini_get_class (method, token, generic_context);
10646                         CHECK_TYPELOAD (klass);
10647
10648                         context_used = mini_class_check_context_used (cfg, klass);
10649
10650                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10651                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10652                                 ins->sreg1 = sp [0]->dreg;
10653                                 ins->type = STACK_I4;
10654                                 ins->dreg = alloc_ireg (cfg);
10655                                 MONO_ADD_INS (cfg->cbb, ins);
10656                                 *sp = mono_decompose_opcode (cfg, ins);
10657                         }
10658
10659                         if (context_used) {
10660                                 MonoInst *args [3];
10661                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10662                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10663
10664                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10665
10666                                 /* vtable */
10667                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10668                                         array_class, MONO_RGCTX_INFO_VTABLE);
10669                                 /* array len */
10670                                 args [1] = sp [0];
10671
10672                                 if (managed_alloc)
10673                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10674                                 else
10675                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10676                         } else {
10677                                 if (cfg->opt & MONO_OPT_SHARED) {
10678                                         /* Decompose now to avoid problems with references to the domainvar */
10679                                         MonoInst *iargs [3];
10680
10681                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10682                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10683                                         iargs [2] = sp [0];
10684
10685                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10686                                 } else {
10687                                         /* Decompose later since it is needed by abcrem */
10688                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10689                                         mono_class_vtable (cfg->domain, array_type);
10690                                         CHECK_TYPELOAD (array_type);
10691
10692                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10693                                         ins->dreg = alloc_ireg_ref (cfg);
10694                                         ins->sreg1 = sp [0]->dreg;
10695                                         ins->inst_newa_class = klass;
10696                                         ins->type = STACK_OBJ;
10697                                         ins->klass = array_type;
10698                                         MONO_ADD_INS (cfg->cbb, ins);
10699                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10700                                         cfg->cbb->has_array_access = TRUE;
10701
10702                                         /* Needed so mono_emit_load_get_addr () gets called */
10703                                         mono_get_got_var (cfg);
10704                                 }
10705                         }
10706
10707                         len_ins = sp [0];
10708                         ip += 5;
10709                         *sp++ = ins;
10710                         inline_costs += 1;
10711
10712                         /* 
10713                          * we inline/optimize the initialization sequence if possible.
10714                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10715                          * for small sizes open code the memcpy
10716                          * ensure the rva field is big enough
10717                          */
10718                         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))) {
10719                                 MonoMethod *memcpy_method = get_memcpy_method ();
10720                                 MonoInst *iargs [3];
10721                                 int add_reg = alloc_ireg_mp (cfg);
10722
10723                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10724                                 if (cfg->compile_aot) {
10725                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10726                                 } else {
10727                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10728                                 }
10729                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10730                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10731                                 ip += 11;
10732                         }
10733
10734                         break;
10735                 }
10736                 case CEE_LDLEN:
10737                         CHECK_STACK (1);
10738                         --sp;
10739                         if (sp [0]->type != STACK_OBJ)
10740                                 UNVERIFIED;
10741
10742                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10743                         ins->dreg = alloc_preg (cfg);
10744                         ins->sreg1 = sp [0]->dreg;
10745                         ins->type = STACK_I4;
10746                         /* This flag will be inherited by the decomposition */
10747                         ins->flags |= MONO_INST_FAULT;
10748                         MONO_ADD_INS (cfg->cbb, ins);
10749                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10750                         cfg->cbb->has_array_access = TRUE;
10751                         ip ++;
10752                         *sp++ = ins;
10753                         break;
10754                 case CEE_LDELEMA:
10755                         CHECK_STACK (2);
10756                         sp -= 2;
10757                         CHECK_OPSIZE (5);
10758                         if (sp [0]->type != STACK_OBJ)
10759                                 UNVERIFIED;
10760
10761                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10762
10763                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10764                         CHECK_TYPELOAD (klass);
10765                         /* we need to make sure that this array is exactly the type it needs
10766                          * to be for correctness. the wrappers are lax with their usage
10767                          * so we need to ignore them here
10768                          */
10769                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10770                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10771                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10772                                 CHECK_TYPELOAD (array_class);
10773                         }
10774
10775                         readonly = FALSE;
10776                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10777                         *sp++ = ins;
10778                         ip += 5;
10779                         break;
10780                 case CEE_LDELEM:
10781                 case CEE_LDELEM_I1:
10782                 case CEE_LDELEM_U1:
10783                 case CEE_LDELEM_I2:
10784                 case CEE_LDELEM_U2:
10785                 case CEE_LDELEM_I4:
10786                 case CEE_LDELEM_U4:
10787                 case CEE_LDELEM_I8:
10788                 case CEE_LDELEM_I:
10789                 case CEE_LDELEM_R4:
10790                 case CEE_LDELEM_R8:
10791                 case CEE_LDELEM_REF: {
10792                         MonoInst *addr;
10793
10794                         CHECK_STACK (2);
10795                         sp -= 2;
10796
10797                         if (*ip == CEE_LDELEM) {
10798                                 CHECK_OPSIZE (5);
10799                                 token = read32 (ip + 1);
10800                                 klass = mini_get_class (method, token, generic_context);
10801                                 CHECK_TYPELOAD (klass);
10802                                 mono_class_init (klass);
10803                         }
10804                         else
10805                                 klass = array_access_to_klass (*ip);
10806
10807                         if (sp [0]->type != STACK_OBJ)
10808                                 UNVERIFIED;
10809
10810                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10811
10812                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10813                                 // FIXME-VT: OP_ICONST optimization
10814                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10815                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10816                                 ins->opcode = OP_LOADV_MEMBASE;
10817                         } else if (sp [1]->opcode == OP_ICONST) {
10818                                 int array_reg = sp [0]->dreg;
10819                                 int index_reg = sp [1]->dreg;
10820                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10821
10822                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10823                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10824                         } else {
10825                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10826                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10827                         }
10828                         *sp++ = ins;
10829                         if (*ip == CEE_LDELEM)
10830                                 ip += 5;
10831                         else
10832                                 ++ip;
10833                         break;
10834                 }
10835                 case CEE_STELEM_I:
10836                 case CEE_STELEM_I1:
10837                 case CEE_STELEM_I2:
10838                 case CEE_STELEM_I4:
10839                 case CEE_STELEM_I8:
10840                 case CEE_STELEM_R4:
10841                 case CEE_STELEM_R8:
10842                 case CEE_STELEM_REF:
10843                 case CEE_STELEM: {
10844                         CHECK_STACK (3);
10845                         sp -= 3;
10846
10847                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10848
10849                         if (*ip == CEE_STELEM) {
10850                                 CHECK_OPSIZE (5);
10851                                 token = read32 (ip + 1);
10852                                 klass = mini_get_class (method, token, generic_context);
10853                                 CHECK_TYPELOAD (klass);
10854                                 mono_class_init (klass);
10855                         }
10856                         else
10857                                 klass = array_access_to_klass (*ip);
10858
10859                         if (sp [0]->type != STACK_OBJ)
10860                                 UNVERIFIED;
10861
10862                         emit_array_store (cfg, klass, sp, TRUE);
10863
10864                         if (*ip == CEE_STELEM)
10865                                 ip += 5;
10866                         else
10867                                 ++ip;
10868                         inline_costs += 1;
10869                         break;
10870                 }
10871                 case CEE_CKFINITE: {
10872                         CHECK_STACK (1);
10873                         --sp;
10874
10875                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10876                         ins->sreg1 = sp [0]->dreg;
10877                         ins->dreg = alloc_freg (cfg);
10878                         ins->type = STACK_R8;
10879                         MONO_ADD_INS (bblock, ins);
10880
10881                         *sp++ = mono_decompose_opcode (cfg, ins);
10882
10883                         ++ip;
10884                         break;
10885                 }
10886                 case CEE_REFANYVAL: {
10887                         MonoInst *src_var, *src;
10888
10889                         int klass_reg = alloc_preg (cfg);
10890                         int dreg = alloc_preg (cfg);
10891
10892                         GSHAREDVT_FAILURE (*ip);
10893
10894                         CHECK_STACK (1);
10895                         MONO_INST_NEW (cfg, ins, *ip);
10896                         --sp;
10897                         CHECK_OPSIZE (5);
10898                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10899                         CHECK_TYPELOAD (klass);
10900                         mono_class_init (klass);
10901
10902                         context_used = mini_class_check_context_used (cfg, klass);
10903
10904                         // FIXME:
10905                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10906                         if (!src_var)
10907                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10908                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10909                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10910
10911                         if (context_used) {
10912                                 MonoInst *klass_ins;
10913
10914                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10915                                                 klass, MONO_RGCTX_INFO_KLASS);
10916
10917                                 // FIXME:
10918                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10919                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10920                         } else {
10921                                 mini_emit_class_check (cfg, klass_reg, klass);
10922                         }
10923                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10924                         ins->type = STACK_MP;
10925                         *sp++ = ins;
10926                         ip += 5;
10927                         break;
10928                 }
10929                 case CEE_MKREFANY: {
10930                         MonoInst *loc, *addr;
10931
10932                         GSHAREDVT_FAILURE (*ip);
10933
10934                         CHECK_STACK (1);
10935                         MONO_INST_NEW (cfg, ins, *ip);
10936                         --sp;
10937                         CHECK_OPSIZE (5);
10938                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10939                         CHECK_TYPELOAD (klass);
10940                         mono_class_init (klass);
10941
10942                         context_used = mini_class_check_context_used (cfg, klass);
10943
10944                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10945                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10946
10947                         if (context_used) {
10948                                 MonoInst *const_ins;
10949                                 int type_reg = alloc_preg (cfg);
10950
10951                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10952                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10953                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10954                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10955                         } else if (cfg->compile_aot) {
10956                                 int const_reg = alloc_preg (cfg);
10957                                 int type_reg = alloc_preg (cfg);
10958
10959                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10960                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10961                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10962                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10963                         } else {
10964                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10965                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10966                         }
10967                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10968
10969                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10970                         ins->type = STACK_VTYPE;
10971                         ins->klass = mono_defaults.typed_reference_class;
10972                         *sp++ = ins;
10973                         ip += 5;
10974                         break;
10975                 }
10976                 case CEE_LDTOKEN: {
10977                         gpointer handle;
10978                         MonoClass *handle_class;
10979
10980                         CHECK_STACK_OVF (1);
10981
10982                         CHECK_OPSIZE (5);
10983                         n = read32 (ip + 1);
10984
10985                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10986                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10987                                 handle = mono_method_get_wrapper_data (method, n);
10988                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10989                                 if (handle_class == mono_defaults.typehandle_class)
10990                                         handle = &((MonoClass*)handle)->byval_arg;
10991                         }
10992                         else {
10993                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10994                         }
10995                         if (!handle)
10996                                 LOAD_ERROR;
10997                         mono_class_init (handle_class);
10998                         if (cfg->generic_sharing_context) {
10999                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11000                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11001                                         /* This case handles ldtoken
11002                                            of an open type, like for
11003                                            typeof(Gen<>). */
11004                                         context_used = 0;
11005                                 } else if (handle_class == mono_defaults.typehandle_class) {
11006                                         /* If we get a MONO_TYPE_CLASS
11007                                            then we need to provide the
11008                                            open type, not an
11009                                            instantiation of it. */
11010                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
11011                                                 context_used = 0;
11012                                         else
11013                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11014                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11015                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11016                                 else if (handle_class == mono_defaults.methodhandle_class)
11017                                         context_used = mini_method_check_context_used (cfg, handle);
11018                                 else
11019                                         g_assert_not_reached ();
11020                         }
11021
11022                         if ((cfg->opt & MONO_OPT_SHARED) &&
11023                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11024                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11025                                 MonoInst *addr, *vtvar, *iargs [3];
11026                                 int method_context_used;
11027
11028                                 method_context_used = mini_method_check_context_used (cfg, method);
11029
11030                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11031
11032                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11033                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11034                                 if (method_context_used) {
11035                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11036                                                 method, MONO_RGCTX_INFO_METHOD);
11037                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11038                                 } else {
11039                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11040                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11041                                 }
11042                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11043
11044                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11045
11046                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11047                         } else {
11048                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11049                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11050                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11051                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11052                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11053                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11054
11055                                         mono_class_init (tclass);
11056                                         if (context_used) {
11057                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11058                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11059                                         } else if (cfg->compile_aot) {
11060                                                 if (method->wrapper_type) {
11061                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
11062                                                                 /* Special case for static synchronized wrappers */
11063                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11064                                                         } else {
11065                                                                 /* FIXME: n is not a normal token */
11066                                                                 DISABLE_AOT (cfg);
11067                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11068                                                         }
11069                                                 } else {
11070                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11071                                                 }
11072                                         } else {
11073                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11074                                         }
11075                                         ins->type = STACK_OBJ;
11076                                         ins->klass = cmethod->klass;
11077                                         ip += 5;
11078                                 } else {
11079                                         MonoInst *addr, *vtvar;
11080
11081                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11082
11083                                         if (context_used) {
11084                                                 if (handle_class == mono_defaults.typehandle_class) {
11085                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11086                                                                         mono_class_from_mono_type (handle),
11087                                                                         MONO_RGCTX_INFO_TYPE);
11088                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11089                                                         ins = emit_get_rgctx_method (cfg, context_used,
11090                                                                         handle, MONO_RGCTX_INFO_METHOD);
11091                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11092                                                         ins = emit_get_rgctx_field (cfg, context_used,
11093                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11094                                                 } else {
11095                                                         g_assert_not_reached ();
11096                                                 }
11097                                         } else if (cfg->compile_aot) {
11098                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11099                                         } else {
11100                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11101                                         }
11102                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11103                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11104                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11105                                 }
11106                         }
11107
11108                         *sp++ = ins;
11109                         ip += 5;
11110                         break;
11111                 }
11112                 case CEE_THROW:
11113                         CHECK_STACK (1);
11114                         MONO_INST_NEW (cfg, ins, OP_THROW);
11115                         --sp;
11116                         ins->sreg1 = sp [0]->dreg;
11117                         ip++;
11118                         bblock->out_of_line = TRUE;
11119                         MONO_ADD_INS (bblock, ins);
11120                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11121                         MONO_ADD_INS (bblock, ins);
11122                         sp = stack_start;
11123                         
11124                         link_bblock (cfg, bblock, end_bblock);
11125                         start_new_bblock = 1;
11126                         break;
11127                 case CEE_ENDFINALLY:
11128                         /* mono_save_seq_point_info () depends on this */
11129                         if (sp != stack_start)
11130                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11131                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11132                         MONO_ADD_INS (bblock, ins);
11133                         ip++;
11134                         start_new_bblock = 1;
11135
11136                         /*
11137                          * Control will leave the method so empty the stack, otherwise
11138                          * the next basic block will start with a nonempty stack.
11139                          */
11140                         while (sp != stack_start) {
11141                                 sp--;
11142                         }
11143                         break;
11144                 case CEE_LEAVE:
11145                 case CEE_LEAVE_S: {
11146                         GList *handlers;
11147
11148                         if (*ip == CEE_LEAVE) {
11149                                 CHECK_OPSIZE (5);
11150                                 target = ip + 5 + (gint32)read32(ip + 1);
11151                         } else {
11152                                 CHECK_OPSIZE (2);
11153                                 target = ip + 2 + (signed char)(ip [1]);
11154                         }
11155
11156                         /* empty the stack */
11157                         while (sp != stack_start) {
11158                                 sp--;
11159                         }
11160
11161                         /* 
11162                          * If this leave statement is in a catch block, check for a
11163                          * pending exception, and rethrow it if necessary.
11164                          * We avoid doing this in runtime invoke wrappers, since those are called
11165                          * by native code which excepts the wrapper to catch all exceptions.
11166                          */
11167                         for (i = 0; i < header->num_clauses; ++i) {
11168                                 MonoExceptionClause *clause = &header->clauses [i];
11169
11170                                 /* 
11171                                  * Use <= in the final comparison to handle clauses with multiple
11172                                  * leave statements, like in bug #78024.
11173                                  * The ordering of the exception clauses guarantees that we find the
11174                                  * innermost clause.
11175                                  */
11176                                 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) {
11177                                         MonoInst *exc_ins;
11178                                         MonoBasicBlock *dont_throw;
11179
11180                                         /*
11181                                           MonoInst *load;
11182
11183                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11184                                         */
11185
11186                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11187
11188                                         NEW_BBLOCK (cfg, dont_throw);
11189
11190                                         /*
11191                                          * Currently, we always rethrow the abort exception, despite the 
11192                                          * fact that this is not correct. See thread6.cs for an example. 
11193                                          * But propagating the abort exception is more important than 
11194                                          * getting the sematics right.
11195                                          */
11196                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11197                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11198                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11199
11200                                         MONO_START_BB (cfg, dont_throw);
11201                                         bblock = cfg->cbb;
11202                                 }
11203                         }
11204
11205                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11206                                 GList *tmp;
11207                                 MonoExceptionClause *clause;
11208
11209                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11210                                         clause = tmp->data;
11211                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11212                                         g_assert (tblock);
11213                                         link_bblock (cfg, bblock, tblock);
11214                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11215                                         ins->inst_target_bb = tblock;
11216                                         ins->inst_eh_block = clause;
11217                                         MONO_ADD_INS (bblock, ins);
11218                                         bblock->has_call_handler = 1;
11219                                         if (COMPILE_LLVM (cfg)) {
11220                                                 MonoBasicBlock *target_bb;
11221
11222                                                 /* 
11223                                                  * Link the finally bblock with the target, since it will
11224                                                  * conceptually branch there.
11225                                                  * FIXME: Have to link the bblock containing the endfinally.
11226                                                  */
11227                                                 GET_BBLOCK (cfg, target_bb, target);
11228                                                 link_bblock (cfg, tblock, target_bb);
11229                                         }
11230                                 }
11231                                 g_list_free (handlers);
11232                         } 
11233
11234                         MONO_INST_NEW (cfg, ins, OP_BR);
11235                         MONO_ADD_INS (bblock, ins);
11236                         GET_BBLOCK (cfg, tblock, target);
11237                         link_bblock (cfg, bblock, tblock);
11238                         ins->inst_target_bb = tblock;
11239                         start_new_bblock = 1;
11240
11241                         if (*ip == CEE_LEAVE)
11242                                 ip += 5;
11243                         else
11244                                 ip += 2;
11245
11246                         break;
11247                 }
11248
11249                         /*
11250                          * Mono specific opcodes
11251                          */
11252                 case MONO_CUSTOM_PREFIX: {
11253
11254                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11255
11256                         CHECK_OPSIZE (2);
11257                         switch (ip [1]) {
11258                         case CEE_MONO_ICALL: {
11259                                 gpointer func;
11260                                 MonoJitICallInfo *info;
11261
11262                                 token = read32 (ip + 2);
11263                                 func = mono_method_get_wrapper_data (method, token);
11264                                 info = mono_find_jit_icall_by_addr (func);
11265                                 if (!info)
11266                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11267                                 g_assert (info);
11268
11269                                 CHECK_STACK (info->sig->param_count);
11270                                 sp -= info->sig->param_count;
11271
11272                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11273                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11274                                         *sp++ = ins;
11275
11276                                 ip += 6;
11277                                 inline_costs += 10 * num_calls++;
11278
11279                                 break;
11280                         }
11281                         case CEE_MONO_LDPTR: {
11282                                 gpointer ptr;
11283
11284                                 CHECK_STACK_OVF (1);
11285                                 CHECK_OPSIZE (6);
11286                                 token = read32 (ip + 2);
11287
11288                                 ptr = mono_method_get_wrapper_data (method, token);
11289                                 /* FIXME: Generalize this */
11290                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11291                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11292                                         *sp++ = ins;
11293                                         ip += 6;
11294                                         break;
11295                                 }
11296                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11297                                 *sp++ = ins;
11298                                 ip += 6;
11299                                 inline_costs += 10 * num_calls++;
11300                                 /* Can't embed random pointers into AOT code */
11301                                 DISABLE_AOT (cfg);
11302                                 break;
11303                         }
11304                         case CEE_MONO_JIT_ICALL_ADDR: {
11305                                 MonoJitICallInfo *callinfo;
11306                                 gpointer ptr;
11307
11308                                 CHECK_STACK_OVF (1);
11309                                 CHECK_OPSIZE (6);
11310                                 token = read32 (ip + 2);
11311
11312                                 ptr = mono_method_get_wrapper_data (method, token);
11313                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11314                                 g_assert (callinfo);
11315                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11316                                 *sp++ = ins;
11317                                 ip += 6;
11318                                 inline_costs += 10 * num_calls++;
11319                                 break;
11320                         }
11321                         case CEE_MONO_ICALL_ADDR: {
11322                                 MonoMethod *cmethod;
11323                                 gpointer ptr;
11324
11325                                 CHECK_STACK_OVF (1);
11326                                 CHECK_OPSIZE (6);
11327                                 token = read32 (ip + 2);
11328
11329                                 cmethod = mono_method_get_wrapper_data (method, token);
11330
11331                                 if (cfg->compile_aot) {
11332                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11333                                 } else {
11334                                         ptr = mono_lookup_internal_call (cmethod);
11335                                         g_assert (ptr);
11336                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11337                                 }
11338                                 *sp++ = ins;
11339                                 ip += 6;
11340                                 break;
11341                         }
11342                         case CEE_MONO_VTADDR: {
11343                                 MonoInst *src_var, *src;
11344
11345                                 CHECK_STACK (1);
11346                                 --sp;
11347
11348                                 // FIXME:
11349                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11350                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11351                                 *sp++ = src;
11352                                 ip += 2;
11353                                 break;
11354                         }
11355                         case CEE_MONO_NEWOBJ: {
11356                                 MonoInst *iargs [2];
11357
11358                                 CHECK_STACK_OVF (1);
11359                                 CHECK_OPSIZE (6);
11360                                 token = read32 (ip + 2);
11361                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11362                                 mono_class_init (klass);
11363                                 NEW_DOMAINCONST (cfg, iargs [0]);
11364                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11365                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11366                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11367                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11368                                 ip += 6;
11369                                 inline_costs += 10 * num_calls++;
11370                                 break;
11371                         }
11372                         case CEE_MONO_OBJADDR:
11373                                 CHECK_STACK (1);
11374                                 --sp;
11375                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11376                                 ins->dreg = alloc_ireg_mp (cfg);
11377                                 ins->sreg1 = sp [0]->dreg;
11378                                 ins->type = STACK_MP;
11379                                 MONO_ADD_INS (cfg->cbb, ins);
11380                                 *sp++ = ins;
11381                                 ip += 2;
11382                                 break;
11383                         case CEE_MONO_LDNATIVEOBJ:
11384                                 /*
11385                                  * Similar to LDOBJ, but instead load the unmanaged 
11386                                  * representation of the vtype to the stack.
11387                                  */
11388                                 CHECK_STACK (1);
11389                                 CHECK_OPSIZE (6);
11390                                 --sp;
11391                                 token = read32 (ip + 2);
11392                                 klass = mono_method_get_wrapper_data (method, token);
11393                                 g_assert (klass->valuetype);
11394                                 mono_class_init (klass);
11395
11396                                 {
11397                                         MonoInst *src, *dest, *temp;
11398
11399                                         src = sp [0];
11400                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11401                                         temp->backend.is_pinvoke = 1;
11402                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11403                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11404
11405                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11406                                         dest->type = STACK_VTYPE;
11407                                         dest->klass = klass;
11408
11409                                         *sp ++ = dest;
11410                                         ip += 6;
11411                                 }
11412                                 break;
11413                         case CEE_MONO_RETOBJ: {
11414                                 /*
11415                                  * Same as RET, but return the native representation of a vtype
11416                                  * to the caller.
11417                                  */
11418                                 g_assert (cfg->ret);
11419                                 g_assert (mono_method_signature (method)->pinvoke); 
11420                                 CHECK_STACK (1);
11421                                 --sp;
11422                                 
11423                                 CHECK_OPSIZE (6);
11424                                 token = read32 (ip + 2);    
11425                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11426
11427                                 if (!cfg->vret_addr) {
11428                                         g_assert (cfg->ret_var_is_local);
11429
11430                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11431                                 } else {
11432                                         EMIT_NEW_RETLOADA (cfg, ins);
11433                                 }
11434                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11435                                 
11436                                 if (sp != stack_start)
11437                                         UNVERIFIED;
11438                                 
11439                                 MONO_INST_NEW (cfg, ins, OP_BR);
11440                                 ins->inst_target_bb = end_bblock;
11441                                 MONO_ADD_INS (bblock, ins);
11442                                 link_bblock (cfg, bblock, end_bblock);
11443                                 start_new_bblock = 1;
11444                                 ip += 6;
11445                                 break;
11446                         }
11447                         case CEE_MONO_CISINST:
11448                         case CEE_MONO_CCASTCLASS: {
11449                                 int token;
11450                                 CHECK_STACK (1);
11451                                 --sp;
11452                                 CHECK_OPSIZE (6);
11453                                 token = read32 (ip + 2);
11454                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11455                                 if (ip [1] == CEE_MONO_CISINST)
11456                                         ins = handle_cisinst (cfg, klass, sp [0]);
11457                                 else
11458                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11459                                 bblock = cfg->cbb;
11460                                 *sp++ = ins;
11461                                 ip += 6;
11462                                 break;
11463                         }
11464                         case CEE_MONO_SAVE_LMF:
11465                         case CEE_MONO_RESTORE_LMF:
11466 #ifdef MONO_ARCH_HAVE_LMF_OPS
11467                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11468                                 MONO_ADD_INS (bblock, ins);
11469                                 cfg->need_lmf_area = TRUE;
11470 #endif
11471                                 ip += 2;
11472                                 break;
11473                         case CEE_MONO_CLASSCONST:
11474                                 CHECK_STACK_OVF (1);
11475                                 CHECK_OPSIZE (6);
11476                                 token = read32 (ip + 2);
11477                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11478                                 *sp++ = ins;
11479                                 ip += 6;
11480                                 inline_costs += 10 * num_calls++;
11481                                 break;
11482                         case CEE_MONO_NOT_TAKEN:
11483                                 bblock->out_of_line = TRUE;
11484                                 ip += 2;
11485                                 break;
11486                         case CEE_MONO_TLS: {
11487                                 int key;
11488
11489                                 CHECK_STACK_OVF (1);
11490                                 CHECK_OPSIZE (6);
11491                                 key = (gint32)read32 (ip + 2);
11492                                 g_assert (key < TLS_KEY_NUM);
11493
11494                                 ins = mono_create_tls_get (cfg, key);
11495                                 if (!ins) {
11496                                         if (cfg->compile_aot) {
11497                                                 DISABLE_AOT (cfg);
11498                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11499                                                 ins->dreg = alloc_preg (cfg);
11500                                                 ins->type = STACK_PTR;
11501                                         } else {
11502                                                 g_assert_not_reached ();
11503                                         }
11504                                 }
11505                                 ins->type = STACK_PTR;
11506                                 MONO_ADD_INS (bblock, ins);
11507                                 *sp++ = ins;
11508                                 ip += 6;
11509                                 break;
11510                         }
11511                         case CEE_MONO_DYN_CALL: {
11512                                 MonoCallInst *call;
11513
11514                                 /* It would be easier to call a trampoline, but that would put an
11515                                  * extra frame on the stack, confusing exception handling. So
11516                                  * implement it inline using an opcode for now.
11517                                  */
11518
11519                                 if (!cfg->dyn_call_var) {
11520                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11521                                         /* prevent it from being register allocated */
11522                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11523                                 }
11524
11525                                 /* Has to use a call inst since it local regalloc expects it */
11526                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11527                                 ins = (MonoInst*)call;
11528                                 sp -= 2;
11529                                 ins->sreg1 = sp [0]->dreg;
11530                                 ins->sreg2 = sp [1]->dreg;
11531                                 MONO_ADD_INS (bblock, ins);
11532
11533                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11534
11535                                 ip += 2;
11536                                 inline_costs += 10 * num_calls++;
11537
11538                                 break;
11539                         }
11540                         case CEE_MONO_MEMORY_BARRIER: {
11541                                 CHECK_OPSIZE (5);
11542                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11543                                 ip += 5;
11544                                 break;
11545                         }
11546                         case CEE_MONO_JIT_ATTACH: {
11547                                 MonoInst *args [16];
11548                                 MonoInst *ad_ins, *lmf_ins;
11549                                 MonoBasicBlock *next_bb = NULL;
11550
11551                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11552
11553                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11554                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11555
11556 #if TARGET_WIN32
11557                                 ad_ins = NULL;
11558                                 lmf_ins = NULL;
11559 #else
11560                                 ad_ins = mono_get_domain_intrinsic (cfg);
11561                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11562 #endif
11563
11564                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11565                                         NEW_BBLOCK (cfg, next_bb);
11566
11567                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11568                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11569                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11570
11571                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11572                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11573                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11574                                 }
11575
11576                                 if (cfg->compile_aot) {
11577                                         /* AOT code is only used in the root domain */
11578                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11579                                 } else {
11580                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11581                                 }
11582                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11583                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11584
11585                                 if (next_bb) {
11586                                         MONO_START_BB (cfg, next_bb);
11587                                         bblock = cfg->cbb;
11588                                 }
11589                                 ip += 2;
11590                                 break;
11591                         }
11592                         case CEE_MONO_JIT_DETACH: {
11593                                 MonoInst *args [16];
11594
11595                                 /* Restore the original domain */
11596                                 dreg = alloc_ireg (cfg);
11597                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11598                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11599                                 ip += 2;
11600                                 break;
11601                         }
11602                         default:
11603                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11604                                 break;
11605                         }
11606                         break;
11607                 }
11608
11609                 case CEE_PREFIX1: {
11610                         CHECK_OPSIZE (2);
11611                         switch (ip [1]) {
11612                         case CEE_ARGLIST: {
11613                                 /* somewhat similar to LDTOKEN */
11614                                 MonoInst *addr, *vtvar;
11615                                 CHECK_STACK_OVF (1);
11616                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11617
11618                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11619                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11620
11621                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11622                                 ins->type = STACK_VTYPE;
11623                                 ins->klass = mono_defaults.argumenthandle_class;
11624                                 *sp++ = ins;
11625                                 ip += 2;
11626                                 break;
11627                         }
11628                         case CEE_CEQ:
11629                         case CEE_CGT:
11630                         case CEE_CGT_UN:
11631                         case CEE_CLT:
11632                         case CEE_CLT_UN: {
11633                                 MonoInst *cmp;
11634                                 CHECK_STACK (2);
11635                                 /*
11636                                  * The following transforms:
11637                                  *    CEE_CEQ    into OP_CEQ
11638                                  *    CEE_CGT    into OP_CGT
11639                                  *    CEE_CGT_UN into OP_CGT_UN
11640                                  *    CEE_CLT    into OP_CLT
11641                                  *    CEE_CLT_UN into OP_CLT_UN
11642                                  */
11643                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11644                                 
11645                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11646                                 sp -= 2;
11647                                 cmp->sreg1 = sp [0]->dreg;
11648                                 cmp->sreg2 = sp [1]->dreg;
11649                                 type_from_op (cmp, sp [0], sp [1]);
11650                                 CHECK_TYPE (cmp);
11651                                 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))))
11652                                         cmp->opcode = OP_LCOMPARE;
11653                                 else if (sp [0]->type == STACK_R8)
11654                                         cmp->opcode = OP_FCOMPARE;
11655                                 else
11656                                         cmp->opcode = OP_ICOMPARE;
11657                                 MONO_ADD_INS (bblock, cmp);
11658                                 ins->type = STACK_I4;
11659                                 ins->dreg = alloc_dreg (cfg, ins->type);
11660                                 type_from_op (ins, sp [0], sp [1]);
11661
11662                                 if (cmp->opcode == OP_FCOMPARE) {
11663                                         /*
11664                                          * The backends expect the fceq opcodes to do the
11665                                          * comparison too.
11666                                          */
11667                                         cmp->opcode = OP_NOP;
11668                                         ins->sreg1 = cmp->sreg1;
11669                                         ins->sreg2 = cmp->sreg2;
11670                                 }
11671                                 MONO_ADD_INS (bblock, ins);
11672                                 *sp++ = ins;
11673                                 ip += 2;
11674                                 break;
11675                         }
11676                         case CEE_LDFTN: {
11677                                 MonoInst *argconst;
11678                                 MonoMethod *cil_method;
11679
11680                                 CHECK_STACK_OVF (1);
11681                                 CHECK_OPSIZE (6);
11682                                 n = read32 (ip + 2);
11683                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11684                                 if (!cmethod || mono_loader_get_last_error ())
11685                                         LOAD_ERROR;
11686                                 mono_class_init (cmethod->klass);
11687
11688                                 mono_save_token_info (cfg, image, n, cmethod);
11689
11690                                 context_used = mini_method_check_context_used (cfg, cmethod);
11691
11692                                 cil_method = cmethod;
11693                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11694                                         METHOD_ACCESS_FAILURE;
11695
11696                                 if (mono_security_cas_enabled ()) {
11697                                         if (check_linkdemand (cfg, method, cmethod))
11698                                                 INLINE_FAILURE ("linkdemand");
11699                                         CHECK_CFG_EXCEPTION;
11700                                 } else if (mono_security_core_clr_enabled ()) {
11701                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11702                                 }
11703
11704                                 /* 
11705                                  * Optimize the common case of ldftn+delegate creation
11706                                  */
11707                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11708                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11709                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11710                                                 MonoInst *target_ins;
11711                                                 MonoMethod *invoke;
11712                                                 int invoke_context_used;
11713
11714                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11715                                                 if (!invoke || !mono_method_signature (invoke))
11716                                                         LOAD_ERROR;
11717
11718                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11719
11720                                                 target_ins = sp [-1];
11721
11722                                                 if (mono_security_core_clr_enabled ())
11723                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11724
11725                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11726                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11727                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11728                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11729                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11730                                                         }
11731                                                 }
11732
11733 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11734                                                 /* FIXME: SGEN support */
11735                                                 if (invoke_context_used == 0) {
11736                                                         ip += 6;
11737                                                         if (cfg->verbose_level > 3)
11738                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11739                                                         sp --;
11740                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11741                                                         CHECK_CFG_EXCEPTION;
11742                                                         ip += 5;                        
11743                                                         sp ++;
11744                                                         break;
11745                                                 }
11746 #endif
11747                                         }
11748                                 }
11749
11750                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11751                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11752                                 *sp++ = ins;
11753                                 
11754                                 ip += 6;
11755                                 inline_costs += 10 * num_calls++;
11756                                 break;
11757                         }
11758                         case CEE_LDVIRTFTN: {
11759                                 MonoInst *args [2];
11760
11761                                 CHECK_STACK (1);
11762                                 CHECK_OPSIZE (6);
11763                                 n = read32 (ip + 2);
11764                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11765                                 if (!cmethod || mono_loader_get_last_error ())
11766                                         LOAD_ERROR;
11767                                 mono_class_init (cmethod->klass);
11768  
11769                                 context_used = mini_method_check_context_used (cfg, cmethod);
11770
11771                                 if (mono_security_cas_enabled ()) {
11772                                         if (check_linkdemand (cfg, method, cmethod))
11773                                                 INLINE_FAILURE ("linkdemand");
11774                                         CHECK_CFG_EXCEPTION;
11775                                 } else if (mono_security_core_clr_enabled ()) {
11776                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11777                                 }
11778
11779                                 --sp;
11780                                 args [0] = *sp;
11781
11782                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11783                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11784
11785                                 if (context_used)
11786                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11787                                 else
11788                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11789
11790                                 ip += 6;
11791                                 inline_costs += 10 * num_calls++;
11792                                 break;
11793                         }
11794                         case CEE_LDARG:
11795                                 CHECK_STACK_OVF (1);
11796                                 CHECK_OPSIZE (4);
11797                                 n = read16 (ip + 2);
11798                                 CHECK_ARG (n);
11799                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11800                                 *sp++ = ins;
11801                                 ip += 4;
11802                                 break;
11803                         case CEE_LDARGA:
11804                                 CHECK_STACK_OVF (1);
11805                                 CHECK_OPSIZE (4);
11806                                 n = read16 (ip + 2);
11807                                 CHECK_ARG (n);
11808                                 NEW_ARGLOADA (cfg, ins, n);
11809                                 MONO_ADD_INS (cfg->cbb, ins);
11810                                 *sp++ = ins;
11811                                 ip += 4;
11812                                 break;
11813                         case CEE_STARG:
11814                                 CHECK_STACK (1);
11815                                 --sp;
11816                                 CHECK_OPSIZE (4);
11817                                 n = read16 (ip + 2);
11818                                 CHECK_ARG (n);
11819                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11820                                         UNVERIFIED;
11821                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11822                                 ip += 4;
11823                                 break;
11824                         case CEE_LDLOC:
11825                                 CHECK_STACK_OVF (1);
11826                                 CHECK_OPSIZE (4);
11827                                 n = read16 (ip + 2);
11828                                 CHECK_LOCAL (n);
11829                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11830                                 *sp++ = ins;
11831                                 ip += 4;
11832                                 break;
11833                         case CEE_LDLOCA: {
11834                                 unsigned char *tmp_ip;
11835                                 CHECK_STACK_OVF (1);
11836                                 CHECK_OPSIZE (4);
11837                                 n = read16 (ip + 2);
11838                                 CHECK_LOCAL (n);
11839
11840                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11841                                         ip = tmp_ip;
11842                                         inline_costs += 1;
11843                                         break;
11844                                 }                       
11845                                 
11846                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11847                                 *sp++ = ins;
11848                                 ip += 4;
11849                                 break;
11850                         }
11851                         case CEE_STLOC:
11852                                 CHECK_STACK (1);
11853                                 --sp;
11854                                 CHECK_OPSIZE (4);
11855                                 n = read16 (ip + 2);
11856                                 CHECK_LOCAL (n);
11857                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11858                                         UNVERIFIED;
11859                                 emit_stloc_ir (cfg, sp, header, n);
11860                                 ip += 4;
11861                                 inline_costs += 1;
11862                                 break;
11863                         case CEE_LOCALLOC:
11864                                 CHECK_STACK (1);
11865                                 --sp;
11866                                 if (sp != stack_start) 
11867                                         UNVERIFIED;
11868                                 if (cfg->method != method) 
11869                                         /* 
11870                                          * Inlining this into a loop in a parent could lead to 
11871                                          * stack overflows which is different behavior than the
11872                                          * non-inlined case, thus disable inlining in this case.
11873                                          */
11874                                         goto inline_failure;
11875
11876                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11877                                 ins->dreg = alloc_preg (cfg);
11878                                 ins->sreg1 = sp [0]->dreg;
11879                                 ins->type = STACK_PTR;
11880                                 MONO_ADD_INS (cfg->cbb, ins);
11881
11882                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11883                                 if (init_locals)
11884                                         ins->flags |= MONO_INST_INIT;
11885
11886                                 *sp++ = ins;
11887                                 ip += 2;
11888                                 break;
11889                         case CEE_ENDFILTER: {
11890                                 MonoExceptionClause *clause, *nearest;
11891                                 int cc, nearest_num;
11892
11893                                 CHECK_STACK (1);
11894                                 --sp;
11895                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11896                                         UNVERIFIED;
11897                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11898                                 ins->sreg1 = (*sp)->dreg;
11899                                 MONO_ADD_INS (bblock, ins);
11900                                 start_new_bblock = 1;
11901                                 ip += 2;
11902
11903                                 nearest = NULL;
11904                                 nearest_num = 0;
11905                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11906                                         clause = &header->clauses [cc];
11907                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11908                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11909                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11910                                                 nearest = clause;
11911                                                 nearest_num = cc;
11912                                         }
11913                                 }
11914                                 g_assert (nearest);
11915                                 if ((ip - header->code) != nearest->handler_offset)
11916                                         UNVERIFIED;
11917
11918                                 break;
11919                         }
11920                         case CEE_UNALIGNED_:
11921                                 ins_flag |= MONO_INST_UNALIGNED;
11922                                 /* FIXME: record alignment? we can assume 1 for now */
11923                                 CHECK_OPSIZE (3);
11924                                 ip += 3;
11925                                 break;
11926                         case CEE_VOLATILE_:
11927                                 ins_flag |= MONO_INST_VOLATILE;
11928                                 ip += 2;
11929                                 break;
11930                         case CEE_TAIL_:
11931                                 ins_flag   |= MONO_INST_TAILCALL;
11932                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11933                                 /* Can't inline tail calls at this time */
11934                                 inline_costs += 100000;
11935                                 ip += 2;
11936                                 break;
11937                         case CEE_INITOBJ:
11938                                 CHECK_STACK (1);
11939                                 --sp;
11940                                 CHECK_OPSIZE (6);
11941                                 token = read32 (ip + 2);
11942                                 klass = mini_get_class (method, token, generic_context);
11943                                 CHECK_TYPELOAD (klass);
11944                                 if (generic_class_is_reference_type (cfg, klass))
11945                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11946                                 else
11947                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11948                                 ip += 6;
11949                                 inline_costs += 1;
11950                                 break;
11951                         case CEE_CONSTRAINED_:
11952                                 CHECK_OPSIZE (6);
11953                                 token = read32 (ip + 2);
11954                                 constrained_call = mini_get_class (method, token, generic_context);
11955                                 CHECK_TYPELOAD (constrained_call);
11956                                 ip += 6;
11957                                 break;
11958                         case CEE_CPBLK:
11959                         case CEE_INITBLK: {
11960                                 MonoInst *iargs [3];
11961                                 CHECK_STACK (3);
11962                                 sp -= 3;
11963
11964                                 /* Skip optimized paths for volatile operations. */
11965                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11966                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11967                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (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)) {
11968                                         /* emit_memset only works when val == 0 */
11969                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11970                                 } else {
11971                                         MonoInst *call;
11972                                         iargs [0] = sp [0];
11973                                         iargs [1] = sp [1];
11974                                         iargs [2] = sp [2];
11975                                         if (ip [1] == CEE_CPBLK) {
11976                                                 /*
11977                                                  * FIXME: It's unclear whether we should be emitting both the acquire
11978                                                  * and release barriers for cpblk. It is technically both a load and
11979                                                  * store operation, so it seems like that's the sensible thing to do.
11980                                                  */
11981                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11982                                                 if (ins_flag & MONO_INST_VOLATILE) {
11983                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11984                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11985                                                         emit_memory_barrier (cfg, FullBarrier);
11986                                                 }
11987                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11988                                                 call->flags |= ins_flag;
11989                                                 if (ins_flag & MONO_INST_VOLATILE) {
11990                                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11991                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11992                                                         emit_memory_barrier (cfg, FullBarrier);
11993                                                 }
11994                                         } else {
11995                                                 MonoMethod *memset_method = get_memset_method ();
11996                                                 if (ins_flag & MONO_INST_VOLATILE) {
11997                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11998                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11999                                                         emit_memory_barrier (cfg, FullBarrier);
12000                                                 }
12001                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12002                                                 call->flags |= ins_flag;
12003                                         }
12004                                 }
12005                                 ip += 2;
12006                                 ins_flag = 0;
12007                                 inline_costs += 1;
12008                                 break;
12009                         }
12010                         case CEE_NO_:
12011                                 CHECK_OPSIZE (3);
12012                                 if (ip [2] & 0x1)
12013                                         ins_flag |= MONO_INST_NOTYPECHECK;
12014                                 if (ip [2] & 0x2)
12015                                         ins_flag |= MONO_INST_NORANGECHECK;
12016                                 /* we ignore the no-nullcheck for now since we
12017                                  * really do it explicitly only when doing callvirt->call
12018                                  */
12019                                 ip += 3;
12020                                 break;
12021                         case CEE_RETHROW: {
12022                                 MonoInst *load;
12023                                 int handler_offset = -1;
12024
12025                                 for (i = 0; i < header->num_clauses; ++i) {
12026                                         MonoExceptionClause *clause = &header->clauses [i];
12027                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12028                                                 handler_offset = clause->handler_offset;
12029                                                 break;
12030                                         }
12031                                 }
12032
12033                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12034
12035                                 g_assert (handler_offset != -1);
12036
12037                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12038                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12039                                 ins->sreg1 = load->dreg;
12040                                 MONO_ADD_INS (bblock, ins);
12041
12042                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12043                                 MONO_ADD_INS (bblock, ins);
12044
12045                                 sp = stack_start;
12046                                 link_bblock (cfg, bblock, end_bblock);
12047                                 start_new_bblock = 1;
12048                                 ip += 2;
12049                                 break;
12050                         }
12051                         case CEE_SIZEOF: {
12052                                 guint32 val;
12053                                 int ialign;
12054
12055                                 GSHAREDVT_FAILURE (*ip);
12056
12057                                 CHECK_STACK_OVF (1);
12058                                 CHECK_OPSIZE (6);
12059                                 token = read32 (ip + 2);
12060                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
12061                                         MonoType *type = mono_type_create_from_typespec (image, token);
12062                                         val = mono_type_size (type, &ialign);
12063                                 } else {
12064                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
12065                                         CHECK_TYPELOAD (klass);
12066                                         mono_class_init (klass);
12067                                         val = mono_type_size (&klass->byval_arg, &ialign);
12068                                 }
12069                                 EMIT_NEW_ICONST (cfg, ins, val);
12070                                 *sp++= ins;
12071                                 ip += 6;
12072                                 break;
12073                         }
12074                         case CEE_REFANYTYPE: {
12075                                 MonoInst *src_var, *src;
12076
12077                                 GSHAREDVT_FAILURE (*ip);
12078
12079                                 CHECK_STACK (1);
12080                                 --sp;
12081
12082                                 // FIXME:
12083                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12084                                 if (!src_var)
12085                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12086                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12087                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
12088                                 *sp++ = ins;
12089                                 ip += 2;
12090                                 break;
12091                         }
12092                         case CEE_READONLY_:
12093                                 readonly = TRUE;
12094                                 ip += 2;
12095                                 break;
12096
12097                         case CEE_UNUSED56:
12098                         case CEE_UNUSED57:
12099                         case CEE_UNUSED70:
12100                         case CEE_UNUSED:
12101                         case CEE_UNUSED99:
12102                                 UNVERIFIED;
12103                                 
12104                         default:
12105                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12106                                 UNVERIFIED;
12107                         }
12108                         break;
12109                 }
12110                 case CEE_UNUSED58:
12111                 case CEE_UNUSED1:
12112                         UNVERIFIED;
12113
12114                 default:
12115                         g_warning ("opcode 0x%02x not handled", *ip);
12116                         UNVERIFIED;
12117                 }
12118         }
12119         if (start_new_bblock != 1)
12120                 UNVERIFIED;
12121
12122         bblock->cil_length = ip - bblock->cil_code;
12123         if (bblock->next_bb) {
12124                 /* This could already be set because of inlining, #693905 */
12125                 MonoBasicBlock *bb = bblock;
12126
12127                 while (bb->next_bb)
12128                         bb = bb->next_bb;
12129                 bb->next_bb = end_bblock;
12130         } else {
12131                 bblock->next_bb = end_bblock;
12132         }
12133
12134         if (cfg->method == method && cfg->domainvar) {
12135                 MonoInst *store;
12136                 MonoInst *get_domain;
12137
12138                 cfg->cbb = init_localsbb;
12139
12140                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12141                         MONO_ADD_INS (cfg->cbb, get_domain);
12142                 } else {
12143                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12144                 }
12145                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12146                 MONO_ADD_INS (cfg->cbb, store);
12147         }
12148
12149 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12150         if (cfg->compile_aot)
12151                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12152                 mono_get_got_var (cfg);
12153 #endif
12154
12155         if (cfg->method == method && cfg->got_var)
12156                 mono_emit_load_got_addr (cfg);
12157
12158         if (init_localsbb) {
12159                 cfg->cbb = init_localsbb;
12160                 cfg->ip = NULL;
12161                 for (i = 0; i < header->num_locals; ++i) {
12162                         emit_init_local (cfg, i, header->locals [i], init_locals);
12163                 }
12164         }
12165
12166         if (cfg->init_ref_vars && cfg->method == method) {
12167                 /* Emit initialization for ref vars */
12168                 // FIXME: Avoid duplication initialization for IL locals.
12169                 for (i = 0; i < cfg->num_varinfo; ++i) {
12170                         MonoInst *ins = cfg->varinfo [i];
12171
12172                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12173                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12174                 }
12175         }
12176
12177         if (cfg->lmf_var && cfg->method == method) {
12178                 cfg->cbb = init_localsbb;
12179                 emit_push_lmf (cfg);
12180         }
12181
12182         if (seq_points) {
12183                 MonoBasicBlock *bb;
12184
12185                 /*
12186                  * Make seq points at backward branch targets interruptable.
12187                  */
12188                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12189                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12190                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12191         }
12192
12193         /* Add a sequence point for method entry/exit events */
12194         if (seq_points) {
12195                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12196                 MONO_ADD_INS (init_localsbb, ins);
12197                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12198                 MONO_ADD_INS (cfg->bb_exit, ins);
12199         }
12200
12201         /*
12202          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12203          * the code they refer to was dead (#11880).
12204          */
12205         if (sym_seq_points) {
12206                 for (i = 0; i < header->code_size; ++i) {
12207                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12208                                 MonoInst *ins;
12209
12210                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12211                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12212                         }
12213                 }
12214         }
12215
12216         cfg->ip = NULL;
12217
12218         if (cfg->method == method) {
12219                 MonoBasicBlock *bb;
12220                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12221                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12222                         if (cfg->spvars)
12223                                 mono_create_spvar_for_region (cfg, bb->region);
12224                         if (cfg->verbose_level > 2)
12225                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12226                 }
12227         }
12228
12229         g_slist_free (class_inits);
12230         dont_inline = g_list_remove (dont_inline, method);
12231
12232         if (inline_costs < 0) {
12233                 char *mname;
12234
12235                 /* Method is too large */
12236                 mname = mono_method_full_name (method, TRUE);
12237                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12238                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12239                 g_free (mname);
12240                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12241                 mono_basic_block_free (original_bb);
12242                 return -1;
12243         }
12244
12245         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12246                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12247
12248         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12249         mono_basic_block_free (original_bb);
12250         return inline_costs;
12251  
12252  exception_exit:
12253         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12254         goto cleanup;
12255
12256  inline_failure:
12257         goto cleanup;
12258
12259  load_error:
12260         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
12261         goto cleanup;
12262
12263  unverified:
12264         set_exception_type_from_invalid_il (cfg, method, ip);
12265         goto cleanup;
12266
12267  cleanup:
12268         g_slist_free (class_inits);
12269         mono_basic_block_free (original_bb);
12270         dont_inline = g_list_remove (dont_inline, method);
12271         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12272         return -1;
12273 }
12274
12275 static int
12276 store_membase_reg_to_store_membase_imm (int opcode)
12277 {
12278         switch (opcode) {
12279         case OP_STORE_MEMBASE_REG:
12280                 return OP_STORE_MEMBASE_IMM;
12281         case OP_STOREI1_MEMBASE_REG:
12282                 return OP_STOREI1_MEMBASE_IMM;
12283         case OP_STOREI2_MEMBASE_REG:
12284                 return OP_STOREI2_MEMBASE_IMM;
12285         case OP_STOREI4_MEMBASE_REG:
12286                 return OP_STOREI4_MEMBASE_IMM;
12287         case OP_STOREI8_MEMBASE_REG:
12288                 return OP_STOREI8_MEMBASE_IMM;
12289         default:
12290                 g_assert_not_reached ();
12291         }
12292
12293         return -1;
12294 }               
12295
12296 int
12297 mono_op_to_op_imm (int opcode)
12298 {
12299         switch (opcode) {
12300         case OP_IADD:
12301                 return OP_IADD_IMM;
12302         case OP_ISUB:
12303                 return OP_ISUB_IMM;
12304         case OP_IDIV:
12305                 return OP_IDIV_IMM;
12306         case OP_IDIV_UN:
12307                 return OP_IDIV_UN_IMM;
12308         case OP_IREM:
12309                 return OP_IREM_IMM;
12310         case OP_IREM_UN:
12311                 return OP_IREM_UN_IMM;
12312         case OP_IMUL:
12313                 return OP_IMUL_IMM;
12314         case OP_IAND:
12315                 return OP_IAND_IMM;
12316         case OP_IOR:
12317                 return OP_IOR_IMM;
12318         case OP_IXOR:
12319                 return OP_IXOR_IMM;
12320         case OP_ISHL:
12321                 return OP_ISHL_IMM;
12322         case OP_ISHR:
12323                 return OP_ISHR_IMM;
12324         case OP_ISHR_UN:
12325                 return OP_ISHR_UN_IMM;
12326
12327         case OP_LADD:
12328                 return OP_LADD_IMM;
12329         case OP_LSUB:
12330                 return OP_LSUB_IMM;
12331         case OP_LAND:
12332                 return OP_LAND_IMM;
12333         case OP_LOR:
12334                 return OP_LOR_IMM;
12335         case OP_LXOR:
12336                 return OP_LXOR_IMM;
12337         case OP_LSHL:
12338                 return OP_LSHL_IMM;
12339         case OP_LSHR:
12340                 return OP_LSHR_IMM;
12341         case OP_LSHR_UN:
12342                 return OP_LSHR_UN_IMM;          
12343
12344         case OP_COMPARE:
12345                 return OP_COMPARE_IMM;
12346         case OP_ICOMPARE:
12347                 return OP_ICOMPARE_IMM;
12348         case OP_LCOMPARE:
12349                 return OP_LCOMPARE_IMM;
12350
12351         case OP_STORE_MEMBASE_REG:
12352                 return OP_STORE_MEMBASE_IMM;
12353         case OP_STOREI1_MEMBASE_REG:
12354                 return OP_STOREI1_MEMBASE_IMM;
12355         case OP_STOREI2_MEMBASE_REG:
12356                 return OP_STOREI2_MEMBASE_IMM;
12357         case OP_STOREI4_MEMBASE_REG:
12358                 return OP_STOREI4_MEMBASE_IMM;
12359
12360 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12361         case OP_X86_PUSH:
12362                 return OP_X86_PUSH_IMM;
12363         case OP_X86_COMPARE_MEMBASE_REG:
12364                 return OP_X86_COMPARE_MEMBASE_IMM;
12365 #endif
12366 #if defined(TARGET_AMD64)
12367         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12368                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12369 #endif
12370         case OP_VOIDCALL_REG:
12371                 return OP_VOIDCALL;
12372         case OP_CALL_REG:
12373                 return OP_CALL;
12374         case OP_LCALL_REG:
12375                 return OP_LCALL;
12376         case OP_FCALL_REG:
12377                 return OP_FCALL;
12378         case OP_LOCALLOC:
12379                 return OP_LOCALLOC_IMM;
12380         }
12381
12382         return -1;
12383 }
12384
12385 static int
12386 ldind_to_load_membase (int opcode)
12387 {
12388         switch (opcode) {
12389         case CEE_LDIND_I1:
12390                 return OP_LOADI1_MEMBASE;
12391         case CEE_LDIND_U1:
12392                 return OP_LOADU1_MEMBASE;
12393         case CEE_LDIND_I2:
12394                 return OP_LOADI2_MEMBASE;
12395         case CEE_LDIND_U2:
12396                 return OP_LOADU2_MEMBASE;
12397         case CEE_LDIND_I4:
12398                 return OP_LOADI4_MEMBASE;
12399         case CEE_LDIND_U4:
12400                 return OP_LOADU4_MEMBASE;
12401         case CEE_LDIND_I:
12402                 return OP_LOAD_MEMBASE;
12403         case CEE_LDIND_REF:
12404                 return OP_LOAD_MEMBASE;
12405         case CEE_LDIND_I8:
12406                 return OP_LOADI8_MEMBASE;
12407         case CEE_LDIND_R4:
12408                 return OP_LOADR4_MEMBASE;
12409         case CEE_LDIND_R8:
12410                 return OP_LOADR8_MEMBASE;
12411         default:
12412                 g_assert_not_reached ();
12413         }
12414
12415         return -1;
12416 }
12417
12418 static int
12419 stind_to_store_membase (int opcode)
12420 {
12421         switch (opcode) {
12422         case CEE_STIND_I1:
12423                 return OP_STOREI1_MEMBASE_REG;
12424         case CEE_STIND_I2:
12425                 return OP_STOREI2_MEMBASE_REG;
12426         case CEE_STIND_I4:
12427                 return OP_STOREI4_MEMBASE_REG;
12428         case CEE_STIND_I:
12429         case CEE_STIND_REF:
12430                 return OP_STORE_MEMBASE_REG;
12431         case CEE_STIND_I8:
12432                 return OP_STOREI8_MEMBASE_REG;
12433         case CEE_STIND_R4:
12434                 return OP_STORER4_MEMBASE_REG;
12435         case CEE_STIND_R8:
12436                 return OP_STORER8_MEMBASE_REG;
12437         default:
12438                 g_assert_not_reached ();
12439         }
12440
12441         return -1;
12442 }
12443
12444 int
12445 mono_load_membase_to_load_mem (int opcode)
12446 {
12447         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12448 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12449         switch (opcode) {
12450         case OP_LOAD_MEMBASE:
12451                 return OP_LOAD_MEM;
12452         case OP_LOADU1_MEMBASE:
12453                 return OP_LOADU1_MEM;
12454         case OP_LOADU2_MEMBASE:
12455                 return OP_LOADU2_MEM;
12456         case OP_LOADI4_MEMBASE:
12457                 return OP_LOADI4_MEM;
12458         case OP_LOADU4_MEMBASE:
12459                 return OP_LOADU4_MEM;
12460 #if SIZEOF_REGISTER == 8
12461         case OP_LOADI8_MEMBASE:
12462                 return OP_LOADI8_MEM;
12463 #endif
12464         }
12465 #endif
12466
12467         return -1;
12468 }
12469
12470 static inline int
12471 op_to_op_dest_membase (int store_opcode, int opcode)
12472 {
12473 #if defined(TARGET_X86)
12474         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12475                 return -1;
12476
12477         switch (opcode) {
12478         case OP_IADD:
12479                 return OP_X86_ADD_MEMBASE_REG;
12480         case OP_ISUB:
12481                 return OP_X86_SUB_MEMBASE_REG;
12482         case OP_IAND:
12483                 return OP_X86_AND_MEMBASE_REG;
12484         case OP_IOR:
12485                 return OP_X86_OR_MEMBASE_REG;
12486         case OP_IXOR:
12487                 return OP_X86_XOR_MEMBASE_REG;
12488         case OP_ADD_IMM:
12489         case OP_IADD_IMM:
12490                 return OP_X86_ADD_MEMBASE_IMM;
12491         case OP_SUB_IMM:
12492         case OP_ISUB_IMM:
12493                 return OP_X86_SUB_MEMBASE_IMM;
12494         case OP_AND_IMM:
12495         case OP_IAND_IMM:
12496                 return OP_X86_AND_MEMBASE_IMM;
12497         case OP_OR_IMM:
12498         case OP_IOR_IMM:
12499                 return OP_X86_OR_MEMBASE_IMM;
12500         case OP_XOR_IMM:
12501         case OP_IXOR_IMM:
12502                 return OP_X86_XOR_MEMBASE_IMM;
12503         case OP_MOVE:
12504                 return OP_NOP;
12505         }
12506 #endif
12507
12508 #if defined(TARGET_AMD64)
12509         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12510                 return -1;
12511
12512         switch (opcode) {
12513         case OP_IADD:
12514                 return OP_X86_ADD_MEMBASE_REG;
12515         case OP_ISUB:
12516                 return OP_X86_SUB_MEMBASE_REG;
12517         case OP_IAND:
12518                 return OP_X86_AND_MEMBASE_REG;
12519         case OP_IOR:
12520                 return OP_X86_OR_MEMBASE_REG;
12521         case OP_IXOR:
12522                 return OP_X86_XOR_MEMBASE_REG;
12523         case OP_IADD_IMM:
12524                 return OP_X86_ADD_MEMBASE_IMM;
12525         case OP_ISUB_IMM:
12526                 return OP_X86_SUB_MEMBASE_IMM;
12527         case OP_IAND_IMM:
12528                 return OP_X86_AND_MEMBASE_IMM;
12529         case OP_IOR_IMM:
12530                 return OP_X86_OR_MEMBASE_IMM;
12531         case OP_IXOR_IMM:
12532                 return OP_X86_XOR_MEMBASE_IMM;
12533         case OP_LADD:
12534                 return OP_AMD64_ADD_MEMBASE_REG;
12535         case OP_LSUB:
12536                 return OP_AMD64_SUB_MEMBASE_REG;
12537         case OP_LAND:
12538                 return OP_AMD64_AND_MEMBASE_REG;
12539         case OP_LOR:
12540                 return OP_AMD64_OR_MEMBASE_REG;
12541         case OP_LXOR:
12542                 return OP_AMD64_XOR_MEMBASE_REG;
12543         case OP_ADD_IMM:
12544         case OP_LADD_IMM:
12545                 return OP_AMD64_ADD_MEMBASE_IMM;
12546         case OP_SUB_IMM:
12547         case OP_LSUB_IMM:
12548                 return OP_AMD64_SUB_MEMBASE_IMM;
12549         case OP_AND_IMM:
12550         case OP_LAND_IMM:
12551                 return OP_AMD64_AND_MEMBASE_IMM;
12552         case OP_OR_IMM:
12553         case OP_LOR_IMM:
12554                 return OP_AMD64_OR_MEMBASE_IMM;
12555         case OP_XOR_IMM:
12556         case OP_LXOR_IMM:
12557                 return OP_AMD64_XOR_MEMBASE_IMM;
12558         case OP_MOVE:
12559                 return OP_NOP;
12560         }
12561 #endif
12562
12563         return -1;
12564 }
12565
12566 static inline int
12567 op_to_op_store_membase (int store_opcode, int opcode)
12568 {
12569 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12570         switch (opcode) {
12571         case OP_ICEQ:
12572                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12573                         return OP_X86_SETEQ_MEMBASE;
12574         case OP_CNE:
12575                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12576                         return OP_X86_SETNE_MEMBASE;
12577         }
12578 #endif
12579
12580         return -1;
12581 }
12582
12583 static inline int
12584 op_to_op_src1_membase (int load_opcode, int opcode)
12585 {
12586 #ifdef TARGET_X86
12587         /* FIXME: This has sign extension issues */
12588         /*
12589         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12590                 return OP_X86_COMPARE_MEMBASE8_IMM;
12591         */
12592
12593         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12594                 return -1;
12595
12596         switch (opcode) {
12597         case OP_X86_PUSH:
12598                 return OP_X86_PUSH_MEMBASE;
12599         case OP_COMPARE_IMM:
12600         case OP_ICOMPARE_IMM:
12601                 return OP_X86_COMPARE_MEMBASE_IMM;
12602         case OP_COMPARE:
12603         case OP_ICOMPARE:
12604                 return OP_X86_COMPARE_MEMBASE_REG;
12605         }
12606 #endif
12607
12608 #ifdef TARGET_AMD64
12609         /* FIXME: This has sign extension issues */
12610         /*
12611         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12612                 return OP_X86_COMPARE_MEMBASE8_IMM;
12613         */
12614
12615         switch (opcode) {
12616         case OP_X86_PUSH:
12617 #ifdef __mono_ilp32__
12618                 if (load_opcode == OP_LOADI8_MEMBASE)
12619 #else
12620                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12621 #endif
12622                         return OP_X86_PUSH_MEMBASE;
12623                 break;
12624                 /* FIXME: This only works for 32 bit immediates
12625         case OP_COMPARE_IMM:
12626         case OP_LCOMPARE_IMM:
12627                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12628                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12629                 */
12630         case OP_ICOMPARE_IMM:
12631                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12632                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12633                 break;
12634         case OP_COMPARE:
12635         case OP_LCOMPARE:
12636 #ifdef __mono_ilp32__
12637                 if (load_opcode == OP_LOAD_MEMBASE)
12638                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12639                 if (load_opcode == OP_LOADI8_MEMBASE)
12640 #else
12641                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12642 #endif
12643                         return OP_AMD64_COMPARE_MEMBASE_REG;
12644                 break;
12645         case OP_ICOMPARE:
12646                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12647                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12648                 break;
12649         }
12650 #endif
12651
12652         return -1;
12653 }
12654
12655 static inline int
12656 op_to_op_src2_membase (int load_opcode, int opcode)
12657 {
12658 #ifdef TARGET_X86
12659         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12660                 return -1;
12661         
12662         switch (opcode) {
12663         case OP_COMPARE:
12664         case OP_ICOMPARE:
12665                 return OP_X86_COMPARE_REG_MEMBASE;
12666         case OP_IADD:
12667                 return OP_X86_ADD_REG_MEMBASE;
12668         case OP_ISUB:
12669                 return OP_X86_SUB_REG_MEMBASE;
12670         case OP_IAND:
12671                 return OP_X86_AND_REG_MEMBASE;
12672         case OP_IOR:
12673                 return OP_X86_OR_REG_MEMBASE;
12674         case OP_IXOR:
12675                 return OP_X86_XOR_REG_MEMBASE;
12676         }
12677 #endif
12678
12679 #ifdef TARGET_AMD64
12680 #ifdef __mono_ilp32__
12681         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12682 #else
12683         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12684 #endif
12685                 switch (opcode) {
12686                 case OP_ICOMPARE:
12687                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12688                 case OP_IADD:
12689                         return OP_X86_ADD_REG_MEMBASE;
12690                 case OP_ISUB:
12691                         return OP_X86_SUB_REG_MEMBASE;
12692                 case OP_IAND:
12693                         return OP_X86_AND_REG_MEMBASE;
12694                 case OP_IOR:
12695                         return OP_X86_OR_REG_MEMBASE;
12696                 case OP_IXOR:
12697                         return OP_X86_XOR_REG_MEMBASE;
12698                 }
12699 #ifdef __mono_ilp32__
12700         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12701 #else
12702         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12703 #endif
12704                 switch (opcode) {
12705                 case OP_COMPARE:
12706                 case OP_LCOMPARE:
12707                         return OP_AMD64_COMPARE_REG_MEMBASE;
12708                 case OP_LADD:
12709                         return OP_AMD64_ADD_REG_MEMBASE;
12710                 case OP_LSUB:
12711                         return OP_AMD64_SUB_REG_MEMBASE;
12712                 case OP_LAND:
12713                         return OP_AMD64_AND_REG_MEMBASE;
12714                 case OP_LOR:
12715                         return OP_AMD64_OR_REG_MEMBASE;
12716                 case OP_LXOR:
12717                         return OP_AMD64_XOR_REG_MEMBASE;
12718                 }
12719         }
12720 #endif
12721
12722         return -1;
12723 }
12724
12725 int
12726 mono_op_to_op_imm_noemul (int opcode)
12727 {
12728         switch (opcode) {
12729 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12730         case OP_LSHR:
12731         case OP_LSHL:
12732         case OP_LSHR_UN:
12733                 return -1;
12734 #endif
12735 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12736         case OP_IDIV:
12737         case OP_IDIV_UN:
12738         case OP_IREM:
12739         case OP_IREM_UN:
12740                 return -1;
12741 #endif
12742 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12743         case OP_IMUL:
12744                 return -1;
12745 #endif
12746         default:
12747                 return mono_op_to_op_imm (opcode);
12748         }
12749 }
12750
12751 /**
12752  * mono_handle_global_vregs:
12753  *
12754  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12755  * for them.
12756  */
12757 void
12758 mono_handle_global_vregs (MonoCompile *cfg)
12759 {
12760         gint32 *vreg_to_bb;
12761         MonoBasicBlock *bb;
12762         int i, pos;
12763
12764         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12765
12766 #ifdef MONO_ARCH_SIMD_INTRINSICS
12767         if (cfg->uses_simd_intrinsics)
12768                 mono_simd_simplify_indirection (cfg);
12769 #endif
12770
12771         /* Find local vregs used in more than one bb */
12772         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12773                 MonoInst *ins = bb->code;       
12774                 int block_num = bb->block_num;
12775
12776                 if (cfg->verbose_level > 2)
12777                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12778
12779                 cfg->cbb = bb;
12780                 for (; ins; ins = ins->next) {
12781                         const char *spec = INS_INFO (ins->opcode);
12782                         int regtype = 0, regindex;
12783                         gint32 prev_bb;
12784
12785                         if (G_UNLIKELY (cfg->verbose_level > 2))
12786                                 mono_print_ins (ins);
12787
12788                         g_assert (ins->opcode >= MONO_CEE_LAST);
12789
12790                         for (regindex = 0; regindex < 4; regindex ++) {
12791                                 int vreg = 0;
12792
12793                                 if (regindex == 0) {
12794                                         regtype = spec [MONO_INST_DEST];
12795                                         if (regtype == ' ')
12796                                                 continue;
12797                                         vreg = ins->dreg;
12798                                 } else if (regindex == 1) {
12799                                         regtype = spec [MONO_INST_SRC1];
12800                                         if (regtype == ' ')
12801                                                 continue;
12802                                         vreg = ins->sreg1;
12803                                 } else if (regindex == 2) {
12804                                         regtype = spec [MONO_INST_SRC2];
12805                                         if (regtype == ' ')
12806                                                 continue;
12807                                         vreg = ins->sreg2;
12808                                 } else if (regindex == 3) {
12809                                         regtype = spec [MONO_INST_SRC3];
12810                                         if (regtype == ' ')
12811                                                 continue;
12812                                         vreg = ins->sreg3;
12813                                 }
12814
12815 #if SIZEOF_REGISTER == 4
12816                                 /* In the LLVM case, the long opcodes are not decomposed */
12817                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12818                                         /*
12819                                          * Since some instructions reference the original long vreg,
12820                                          * and some reference the two component vregs, it is quite hard
12821                                          * to determine when it needs to be global. So be conservative.
12822                                          */
12823                                         if (!get_vreg_to_inst (cfg, vreg)) {
12824                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12825
12826                                                 if (cfg->verbose_level > 2)
12827                                                         printf ("LONG VREG R%d made global.\n", vreg);
12828                                         }
12829
12830                                         /*
12831                                          * Make the component vregs volatile since the optimizations can
12832                                          * get confused otherwise.
12833                                          */
12834                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12835                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12836                                 }
12837 #endif
12838
12839                                 g_assert (vreg != -1);
12840
12841                                 prev_bb = vreg_to_bb [vreg];
12842                                 if (prev_bb == 0) {
12843                                         /* 0 is a valid block num */
12844                                         vreg_to_bb [vreg] = block_num + 1;
12845                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12846                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12847                                                 continue;
12848
12849                                         if (!get_vreg_to_inst (cfg, vreg)) {
12850                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12851                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12852
12853                                                 switch (regtype) {
12854                                                 case 'i':
12855                                                         if (vreg_is_ref (cfg, vreg))
12856                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12857                                                         else
12858                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12859                                                         break;
12860                                                 case 'l':
12861                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12862                                                         break;
12863                                                 case 'f':
12864                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12865                                                         break;
12866                                                 case 'v':
12867                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12868                                                         break;
12869                                                 default:
12870                                                         g_assert_not_reached ();
12871                                                 }
12872                                         }
12873
12874                                         /* Flag as having been used in more than one bb */
12875                                         vreg_to_bb [vreg] = -1;
12876                                 }
12877                         }
12878                 }
12879         }
12880
12881         /* If a variable is used in only one bblock, convert it into a local vreg */
12882         for (i = 0; i < cfg->num_varinfo; i++) {
12883                 MonoInst *var = cfg->varinfo [i];
12884                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12885
12886                 switch (var->type) {
12887                 case STACK_I4:
12888                 case STACK_OBJ:
12889                 case STACK_PTR:
12890                 case STACK_MP:
12891                 case STACK_VTYPE:
12892 #if SIZEOF_REGISTER == 8
12893                 case STACK_I8:
12894 #endif
12895 #if !defined(TARGET_X86)
12896                 /* Enabling this screws up the fp stack on x86 */
12897                 case STACK_R8:
12898 #endif
12899                         if (mono_arch_is_soft_float ())
12900                                 break;
12901
12902                         /* Arguments are implicitly global */
12903                         /* Putting R4 vars into registers doesn't work currently */
12904                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12905                         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 && var != cfg->gsharedvt_info_var && var != cfg->gsharedvt_locals_var && var != cfg->lmf_addr_var) {
12906                                 /* 
12907                                  * Make that the variable's liveness interval doesn't contain a call, since
12908                                  * that would cause the lvreg to be spilled, making the whole optimization
12909                                  * useless.
12910                                  */
12911                                 /* This is too slow for JIT compilation */
12912 #if 0
12913                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12914                                         MonoInst *ins;
12915                                         int def_index, call_index, ins_index;
12916                                         gboolean spilled = FALSE;
12917
12918                                         def_index = -1;
12919                                         call_index = -1;
12920                                         ins_index = 0;
12921                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12922                                                 const char *spec = INS_INFO (ins->opcode);
12923
12924                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12925                                                         def_index = ins_index;
12926
12927                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12928                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12929                                                         if (call_index > def_index) {
12930                                                                 spilled = TRUE;
12931                                                                 break;
12932                                                         }
12933                                                 }
12934
12935                                                 if (MONO_IS_CALL (ins))
12936                                                         call_index = ins_index;
12937
12938                                                 ins_index ++;
12939                                         }
12940
12941                                         if (spilled)
12942                                                 break;
12943                                 }
12944 #endif
12945
12946                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12947                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12948                                 var->flags |= MONO_INST_IS_DEAD;
12949                                 cfg->vreg_to_inst [var->dreg] = NULL;
12950                         }
12951                         break;
12952                 }
12953         }
12954
12955         /* 
12956          * Compress the varinfo and vars tables so the liveness computation is faster and
12957          * takes up less space.
12958          */
12959         pos = 0;
12960         for (i = 0; i < cfg->num_varinfo; ++i) {
12961                 MonoInst *var = cfg->varinfo [i];
12962                 if (pos < i && cfg->locals_start == i)
12963                         cfg->locals_start = pos;
12964                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12965                         if (pos < i) {
12966                                 cfg->varinfo [pos] = cfg->varinfo [i];
12967                                 cfg->varinfo [pos]->inst_c0 = pos;
12968                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12969                                 cfg->vars [pos].idx = pos;
12970 #if SIZEOF_REGISTER == 4
12971                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12972                                         /* Modify the two component vars too */
12973                                         MonoInst *var1;
12974
12975                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12976                                         var1->inst_c0 = pos;
12977                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12978                                         var1->inst_c0 = pos;
12979                                 }
12980 #endif
12981                         }
12982                         pos ++;
12983                 }
12984         }
12985         cfg->num_varinfo = pos;
12986         if (cfg->locals_start > cfg->num_varinfo)
12987                 cfg->locals_start = cfg->num_varinfo;
12988 }
12989
12990 /**
12991  * mono_spill_global_vars:
12992  *
12993  *   Generate spill code for variables which are not allocated to registers, 
12994  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12995  * code is generated which could be optimized by the local optimization passes.
12996  */
12997 void
12998 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12999 {
13000         MonoBasicBlock *bb;
13001         char spec2 [16];
13002         int orig_next_vreg;
13003         guint32 *vreg_to_lvreg;
13004         guint32 *lvregs;
13005         guint32 i, lvregs_len;
13006         gboolean dest_has_lvreg = FALSE;
13007         guint32 stacktypes [128];
13008         MonoInst **live_range_start, **live_range_end;
13009         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13010         int *gsharedvt_vreg_to_idx = NULL;
13011
13012         *need_local_opts = FALSE;
13013
13014         memset (spec2, 0, sizeof (spec2));
13015
13016         /* FIXME: Move this function to mini.c */
13017         stacktypes ['i'] = STACK_PTR;
13018         stacktypes ['l'] = STACK_I8;
13019         stacktypes ['f'] = STACK_R8;
13020 #ifdef MONO_ARCH_SIMD_INTRINSICS
13021         stacktypes ['x'] = STACK_VTYPE;
13022 #endif
13023
13024 #if SIZEOF_REGISTER == 4
13025         /* Create MonoInsts for longs */
13026         for (i = 0; i < cfg->num_varinfo; i++) {
13027                 MonoInst *ins = cfg->varinfo [i];
13028
13029                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13030                         switch (ins->type) {
13031                         case STACK_R8:
13032                         case STACK_I8: {
13033                                 MonoInst *tree;
13034
13035                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13036                                         break;
13037
13038                                 g_assert (ins->opcode == OP_REGOFFSET);
13039
13040                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13041                                 g_assert (tree);
13042                                 tree->opcode = OP_REGOFFSET;
13043                                 tree->inst_basereg = ins->inst_basereg;
13044                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13045
13046                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13047                                 g_assert (tree);
13048                                 tree->opcode = OP_REGOFFSET;
13049                                 tree->inst_basereg = ins->inst_basereg;
13050                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13051                                 break;
13052                         }
13053                         default:
13054                                 break;
13055                         }
13056                 }
13057         }
13058 #endif
13059
13060         if (cfg->compute_gc_maps) {
13061                 /* registers need liveness info even for !non refs */
13062                 for (i = 0; i < cfg->num_varinfo; i++) {
13063                         MonoInst *ins = cfg->varinfo [i];
13064
13065                         if (ins->opcode == OP_REGVAR)
13066                                 ins->flags |= MONO_INST_GC_TRACK;
13067                 }
13068         }
13069
13070         if (cfg->gsharedvt) {
13071                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13072
13073                 for (i = 0; i < cfg->num_varinfo; ++i) {
13074                         MonoInst *ins = cfg->varinfo [i];
13075                         int idx;
13076
13077                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13078                                 if (i >= cfg->locals_start) {
13079                                         /* Local */
13080                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13081                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13082                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13083                                         ins->inst_imm = idx;
13084                                 } else {
13085                                         /* Arg */
13086                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13087                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13088                                 }
13089                         }
13090                 }
13091         }
13092                 
13093         /* FIXME: widening and truncation */
13094
13095         /*
13096          * As an optimization, when a variable allocated to the stack is first loaded into 
13097          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13098          * the variable again.
13099          */
13100         orig_next_vreg = cfg->next_vreg;
13101         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13102         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13103         lvregs_len = 0;
13104
13105         /* 
13106          * These arrays contain the first and last instructions accessing a given
13107          * variable.
13108          * Since we emit bblocks in the same order we process them here, and we
13109          * don't split live ranges, these will precisely describe the live range of
13110          * the variable, i.e. the instruction range where a valid value can be found
13111          * in the variables location.
13112          * The live range is computed using the liveness info computed by the liveness pass.
13113          * We can't use vmv->range, since that is an abstract live range, and we need
13114          * one which is instruction precise.
13115          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13116          */
13117         /* FIXME: Only do this if debugging info is requested */
13118         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13119         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13120         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13121         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13122         
13123         /* Add spill loads/stores */
13124         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13125                 MonoInst *ins;
13126
13127                 if (cfg->verbose_level > 2)
13128                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13129
13130                 /* Clear vreg_to_lvreg array */
13131                 for (i = 0; i < lvregs_len; i++)
13132                         vreg_to_lvreg [lvregs [i]] = 0;
13133                 lvregs_len = 0;
13134
13135                 cfg->cbb = bb;
13136                 MONO_BB_FOR_EACH_INS (bb, ins) {
13137                         const char *spec = INS_INFO (ins->opcode);
13138                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13139                         gboolean store, no_lvreg;
13140                         int sregs [MONO_MAX_SRC_REGS];
13141
13142                         if (G_UNLIKELY (cfg->verbose_level > 2))
13143                                 mono_print_ins (ins);
13144
13145                         if (ins->opcode == OP_NOP)
13146                                 continue;
13147
13148                         /* 
13149                          * We handle LDADDR here as well, since it can only be decomposed
13150                          * when variable addresses are known.
13151                          */
13152                         if (ins->opcode == OP_LDADDR) {
13153                                 MonoInst *var = ins->inst_p0;
13154
13155                                 if (var->opcode == OP_VTARG_ADDR) {
13156                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13157                                         MonoInst *vtaddr = var->inst_left;
13158                                         if (vtaddr->opcode == OP_REGVAR) {
13159                                                 ins->opcode = OP_MOVE;
13160                                                 ins->sreg1 = vtaddr->dreg;
13161                                         }
13162                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13163                                                 ins->opcode = OP_LOAD_MEMBASE;
13164                                                 ins->inst_basereg = vtaddr->inst_basereg;
13165                                                 ins->inst_offset = vtaddr->inst_offset;
13166                                         } else
13167                                                 NOT_IMPLEMENTED;
13168                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13169                                         /* gsharedvt arg passed by ref */
13170                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13171
13172                                         ins->opcode = OP_LOAD_MEMBASE;
13173                                         ins->inst_basereg = var->inst_basereg;
13174                                         ins->inst_offset = var->inst_offset;
13175                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13176                                         MonoInst *load, *load2, *load3;
13177                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13178                                         int reg1, reg2, reg3;
13179                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13180                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13181
13182                                         /*
13183                                          * gsharedvt local.
13184                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13185                                          */
13186
13187                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13188
13189                                         g_assert (info_var);
13190                                         g_assert (locals_var);
13191
13192                                         /* Mark the instruction used to compute the locals var as used */
13193                                         cfg->gsharedvt_locals_var_ins = NULL;
13194
13195                                         /* Load the offset */
13196                                         if (info_var->opcode == OP_REGOFFSET) {
13197                                                 reg1 = alloc_ireg (cfg);
13198                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13199                                         } else if (info_var->opcode == OP_REGVAR) {
13200                                                 load = NULL;
13201                                                 reg1 = info_var->dreg;
13202                                         } else {
13203                                                 g_assert_not_reached ();
13204                                         }
13205                                         reg2 = alloc_ireg (cfg);
13206                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13207                                         /* Load the locals area address */
13208                                         reg3 = alloc_ireg (cfg);
13209                                         if (locals_var->opcode == OP_REGOFFSET) {
13210                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13211                                         } else if (locals_var->opcode == OP_REGVAR) {
13212                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13213                                         } else {
13214                                                 g_assert_not_reached ();
13215                                         }
13216                                         /* Compute the address */
13217                                         ins->opcode = OP_PADD;
13218                                         ins->sreg1 = reg3;
13219                                         ins->sreg2 = reg2;
13220
13221                                         mono_bblock_insert_before_ins (bb, ins, load3);
13222                                         mono_bblock_insert_before_ins (bb, load3, load2);
13223                                         if (load)
13224                                                 mono_bblock_insert_before_ins (bb, load2, load);
13225                                 } else {
13226                                         g_assert (var->opcode == OP_REGOFFSET);
13227
13228                                         ins->opcode = OP_ADD_IMM;
13229                                         ins->sreg1 = var->inst_basereg;
13230                                         ins->inst_imm = var->inst_offset;
13231                                 }
13232
13233                                 *need_local_opts = TRUE;
13234                                 spec = INS_INFO (ins->opcode);
13235                         }
13236
13237                         if (ins->opcode < MONO_CEE_LAST) {
13238                                 mono_print_ins (ins);
13239                                 g_assert_not_reached ();
13240                         }
13241
13242                         /*
13243                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13244                          * src register.
13245                          * FIXME:
13246                          */
13247                         if (MONO_IS_STORE_MEMBASE (ins)) {
13248                                 tmp_reg = ins->dreg;
13249                                 ins->dreg = ins->sreg2;
13250                                 ins->sreg2 = tmp_reg;
13251                                 store = TRUE;
13252
13253                                 spec2 [MONO_INST_DEST] = ' ';
13254                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13255                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13256                                 spec2 [MONO_INST_SRC3] = ' ';
13257                                 spec = spec2;
13258                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13259                                 g_assert_not_reached ();
13260                         else
13261                                 store = FALSE;
13262                         no_lvreg = FALSE;
13263
13264                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13265                                 printf ("\t %.3s %d", spec, ins->dreg);
13266                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13267                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13268                                         printf (" %d", sregs [srcindex]);
13269                                 printf ("\n");
13270                         }
13271
13272                         /***************/
13273                         /*    DREG     */
13274                         /***************/
13275                         regtype = spec [MONO_INST_DEST];
13276                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13277                         prev_dreg = -1;
13278
13279                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13280                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13281                                 MonoInst *store_ins;
13282                                 int store_opcode;
13283                                 MonoInst *def_ins = ins;
13284                                 int dreg = ins->dreg; /* The original vreg */
13285
13286                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13287
13288                                 if (var->opcode == OP_REGVAR) {
13289                                         ins->dreg = var->dreg;
13290                                 } 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)) {
13291                                         /* 
13292                                          * Instead of emitting a load+store, use a _membase opcode.
13293                                          */
13294                                         g_assert (var->opcode == OP_REGOFFSET);
13295                                         if (ins->opcode == OP_MOVE) {
13296                                                 NULLIFY_INS (ins);
13297                                                 def_ins = NULL;
13298                                         } else {
13299                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13300                                                 ins->inst_basereg = var->inst_basereg;
13301                                                 ins->inst_offset = var->inst_offset;
13302                                                 ins->dreg = -1;
13303                                         }
13304                                         spec = INS_INFO (ins->opcode);
13305                                 } else {
13306                                         guint32 lvreg;
13307
13308                                         g_assert (var->opcode == OP_REGOFFSET);
13309
13310                                         prev_dreg = ins->dreg;
13311
13312                                         /* Invalidate any previous lvreg for this vreg */
13313                                         vreg_to_lvreg [ins->dreg] = 0;
13314
13315                                         lvreg = 0;
13316
13317                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13318                                                 regtype = 'l';
13319                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13320                                         }
13321
13322                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13323
13324 #if SIZEOF_REGISTER != 8
13325                                         if (regtype == 'l') {
13326                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13327                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13328                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13329                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13330                                                 def_ins = store_ins;
13331                                         }
13332                                         else
13333 #endif
13334                                         {
13335                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13336
13337                                                 /* Try to fuse the store into the instruction itself */
13338                                                 /* FIXME: Add more instructions */
13339                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13340                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13341                                                         ins->inst_imm = ins->inst_c0;
13342                                                         ins->inst_destbasereg = var->inst_basereg;
13343                                                         ins->inst_offset = var->inst_offset;
13344                                                         spec = INS_INFO (ins->opcode);
13345                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13346                                                         ins->opcode = store_opcode;
13347                                                         ins->inst_destbasereg = var->inst_basereg;
13348                                                         ins->inst_offset = var->inst_offset;
13349
13350                                                         no_lvreg = TRUE;
13351
13352                                                         tmp_reg = ins->dreg;
13353                                                         ins->dreg = ins->sreg2;
13354                                                         ins->sreg2 = tmp_reg;
13355                                                         store = TRUE;
13356
13357                                                         spec2 [MONO_INST_DEST] = ' ';
13358                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13359                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13360                                                         spec2 [MONO_INST_SRC3] = ' ';
13361                                                         spec = spec2;
13362                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13363                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13364                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13365                                                         ins->dreg = -1;
13366                                                         ins->inst_basereg = var->inst_basereg;
13367                                                         ins->inst_offset = var->inst_offset;
13368                                                         spec = INS_INFO (ins->opcode);
13369                                                 } else {
13370                                                         /* printf ("INS: "); mono_print_ins (ins); */
13371                                                         /* Create a store instruction */
13372                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13373
13374                                                         /* Insert it after the instruction */
13375                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13376
13377                                                         def_ins = store_ins;
13378
13379                                                         /* 
13380                                                          * We can't assign ins->dreg to var->dreg here, since the
13381                                                          * sregs could use it. So set a flag, and do it after
13382                                                          * the sregs.
13383                                                          */
13384                                                         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)))
13385                                                                 dest_has_lvreg = TRUE;
13386                                                 }
13387                                         }
13388                                 }
13389
13390                                 if (def_ins && !live_range_start [dreg]) {
13391                                         live_range_start [dreg] = def_ins;
13392                                         live_range_start_bb [dreg] = bb;
13393                                 }
13394
13395                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13396                                         MonoInst *tmp;
13397
13398                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13399                                         tmp->inst_c1 = dreg;
13400                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13401                                 }
13402                         }
13403
13404                         /************/
13405                         /*  SREGS   */
13406                         /************/
13407                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13408                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13409                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13410                                 sreg = sregs [srcindex];
13411
13412                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13413                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13414                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13415                                         MonoInst *use_ins = ins;
13416                                         MonoInst *load_ins;
13417                                         guint32 load_opcode;
13418
13419                                         if (var->opcode == OP_REGVAR) {
13420                                                 sregs [srcindex] = var->dreg;
13421                                                 //mono_inst_set_src_registers (ins, sregs);
13422                                                 live_range_end [sreg] = use_ins;
13423                                                 live_range_end_bb [sreg] = bb;
13424
13425                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13426                                                         MonoInst *tmp;
13427
13428                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13429                                                         /* var->dreg is a hreg */
13430                                                         tmp->inst_c1 = sreg;
13431                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13432                                                 }
13433
13434                                                 continue;
13435                                         }
13436
13437                                         g_assert (var->opcode == OP_REGOFFSET);
13438                                                 
13439                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13440
13441                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13442
13443                                         if (vreg_to_lvreg [sreg]) {
13444                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13445
13446                                                 /* The variable is already loaded to an lvreg */
13447                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13448                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13449                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13450                                                 //mono_inst_set_src_registers (ins, sregs);
13451                                                 continue;
13452                                         }
13453
13454                                         /* Try to fuse the load into the instruction */
13455                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13456                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13457                                                 sregs [0] = var->inst_basereg;
13458                                                 //mono_inst_set_src_registers (ins, sregs);
13459                                                 ins->inst_offset = var->inst_offset;
13460                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13461                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13462                                                 sregs [1] = var->inst_basereg;
13463                                                 //mono_inst_set_src_registers (ins, sregs);
13464                                                 ins->inst_offset = var->inst_offset;
13465                                         } else {
13466                                                 if (MONO_IS_REAL_MOVE (ins)) {
13467                                                         ins->opcode = OP_NOP;
13468                                                         sreg = ins->dreg;
13469                                                 } else {
13470                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13471
13472                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13473
13474                                                         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) {
13475                                                                 if (var->dreg == prev_dreg) {
13476                                                                         /*
13477                                                                          * sreg refers to the value loaded by the load
13478                                                                          * emitted below, but we need to use ins->dreg
13479                                                                          * since it refers to the store emitted earlier.
13480                                                                          */
13481                                                                         sreg = ins->dreg;
13482                                                                 }
13483                                                                 g_assert (sreg != -1);
13484                                                                 vreg_to_lvreg [var->dreg] = sreg;
13485                                                                 g_assert (lvregs_len < 1024);
13486                                                                 lvregs [lvregs_len ++] = var->dreg;
13487                                                         }
13488                                                 }
13489
13490                                                 sregs [srcindex] = sreg;
13491                                                 //mono_inst_set_src_registers (ins, sregs);
13492
13493 #if SIZEOF_REGISTER != 8
13494                                                 if (regtype == 'l') {
13495                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13496                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13497                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13498                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13499                                                         use_ins = load_ins;
13500                                                 }
13501                                                 else
13502 #endif
13503                                                 {
13504 #if SIZEOF_REGISTER == 4
13505                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13506 #endif
13507                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13508                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13509                                                         use_ins = load_ins;
13510                                                 }
13511                                         }
13512
13513                                         if (var->dreg < orig_next_vreg) {
13514                                                 live_range_end [var->dreg] = use_ins;
13515                                                 live_range_end_bb [var->dreg] = bb;
13516                                         }
13517
13518                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13519                                                 MonoInst *tmp;
13520
13521                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13522                                                 tmp->inst_c1 = var->dreg;
13523                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13524                                         }
13525                                 }
13526                         }
13527                         mono_inst_set_src_registers (ins, sregs);
13528
13529                         if (dest_has_lvreg) {
13530                                 g_assert (ins->dreg != -1);
13531                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13532                                 g_assert (lvregs_len < 1024);
13533                                 lvregs [lvregs_len ++] = prev_dreg;
13534                                 dest_has_lvreg = FALSE;
13535                         }
13536
13537                         if (store) {
13538                                 tmp_reg = ins->dreg;
13539                                 ins->dreg = ins->sreg2;
13540                                 ins->sreg2 = tmp_reg;
13541                         }
13542
13543                         if (MONO_IS_CALL (ins)) {
13544                                 /* Clear vreg_to_lvreg array */
13545                                 for (i = 0; i < lvregs_len; i++)
13546                                         vreg_to_lvreg [lvregs [i]] = 0;
13547                                 lvregs_len = 0;
13548                         } else if (ins->opcode == OP_NOP) {
13549                                 ins->dreg = -1;
13550                                 MONO_INST_NULLIFY_SREGS (ins);
13551                         }
13552
13553                         if (cfg->verbose_level > 2)
13554                                 mono_print_ins_index (1, ins);
13555                 }
13556
13557                 /* Extend the live range based on the liveness info */
13558                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13559                         for (i = 0; i < cfg->num_varinfo; i ++) {
13560                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13561
13562                                 if (vreg_is_volatile (cfg, vi->vreg))
13563                                         /* The liveness info is incomplete */
13564                                         continue;
13565
13566                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13567                                         /* Live from at least the first ins of this bb */
13568                                         live_range_start [vi->vreg] = bb->code;
13569                                         live_range_start_bb [vi->vreg] = bb;
13570                                 }
13571
13572                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13573                                         /* Live at least until the last ins of this bb */
13574                                         live_range_end [vi->vreg] = bb->last_ins;
13575                                         live_range_end_bb [vi->vreg] = bb;
13576                                 }
13577                         }
13578                 }
13579         }
13580         
13581 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13582         /*
13583          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13584          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13585          */
13586         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13587                 for (i = 0; i < cfg->num_varinfo; ++i) {
13588                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13589                         MonoInst *ins;
13590
13591                         if (live_range_start [vreg]) {
13592                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13593                                 ins->inst_c0 = i;
13594                                 ins->inst_c1 = vreg;
13595                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13596                         }
13597                         if (live_range_end [vreg]) {
13598                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13599                                 ins->inst_c0 = i;
13600                                 ins->inst_c1 = vreg;
13601                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13602                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13603                                 else
13604                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13605                         }
13606                 }
13607         }
13608 #endif
13609
13610         if (cfg->gsharedvt_locals_var_ins) {
13611                 /* Nullify if unused */
13612                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13613                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13614         }
13615
13616         g_free (live_range_start);
13617         g_free (live_range_end);
13618         g_free (live_range_start_bb);
13619         g_free (live_range_end_bb);
13620 }
13621
13622 /**
13623  * FIXME:
13624  * - use 'iadd' instead of 'int_add'
13625  * - handling ovf opcodes: decompose in method_to_ir.
13626  * - unify iregs/fregs
13627  *   -> partly done, the missing parts are:
13628  *   - a more complete unification would involve unifying the hregs as well, so
13629  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13630  *     would no longer map to the machine hregs, so the code generators would need to
13631  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13632  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13633  *     fp/non-fp branches speeds it up by about 15%.
13634  * - use sext/zext opcodes instead of shifts
13635  * - add OP_ICALL
13636  * - get rid of TEMPLOADs if possible and use vregs instead
13637  * - clean up usage of OP_P/OP_ opcodes
13638  * - cleanup usage of DUMMY_USE
13639  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13640  *   stack
13641  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13642  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13643  * - make sure handle_stack_args () is called before the branch is emitted
13644  * - when the new IR is done, get rid of all unused stuff
13645  * - COMPARE/BEQ as separate instructions or unify them ?
13646  *   - keeping them separate allows specialized compare instructions like
13647  *     compare_imm, compare_membase
13648  *   - most back ends unify fp compare+branch, fp compare+ceq
13649  * - integrate mono_save_args into inline_method
13650  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13651  * - handle long shift opts on 32 bit platforms somehow: they require 
13652  *   3 sregs (2 for arg1 and 1 for arg2)
13653  * - make byref a 'normal' type.
13654  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13655  *   variable if needed.
13656  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13657  *   like inline_method.
13658  * - remove inlining restrictions
13659  * - fix LNEG and enable cfold of INEG
13660  * - generalize x86 optimizations like ldelema as a peephole optimization
13661  * - add store_mem_imm for amd64
13662  * - optimize the loading of the interruption flag in the managed->native wrappers
13663  * - avoid special handling of OP_NOP in passes
13664  * - move code inserting instructions into one function/macro.
13665  * - try a coalescing phase after liveness analysis
13666  * - add float -> vreg conversion + local optimizations on !x86
13667  * - figure out how to handle decomposed branches during optimizations, ie.
13668  *   compare+branch, op_jump_table+op_br etc.
13669  * - promote RuntimeXHandles to vregs
13670  * - vtype cleanups:
13671  *   - add a NEW_VARLOADA_VREG macro
13672  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13673  *   accessing vtype fields.
13674  * - get rid of I8CONST on 64 bit platforms
13675  * - dealing with the increase in code size due to branches created during opcode
13676  *   decomposition:
13677  *   - use extended basic blocks
13678  *     - all parts of the JIT
13679  *     - handle_global_vregs () && local regalloc
13680  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13681  * - sources of increase in code size:
13682  *   - vtypes
13683  *   - long compares
13684  *   - isinst and castclass
13685  *   - lvregs not allocated to global registers even if used multiple times
13686  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13687  *   meaningful.
13688  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13689  * - add all micro optimizations from the old JIT
13690  * - put tree optimizations into the deadce pass
13691  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13692  *   specific function.
13693  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13694  *   fcompare + branchCC.
13695  * - create a helper function for allocating a stack slot, taking into account 
13696  *   MONO_CFG_HAS_SPILLUP.
13697  * - merge r68207.
13698  * - merge the ia64 switch changes.
13699  * - optimize mono_regstate2_alloc_int/float.
13700  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13701  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13702  *   parts of the tree could be separated by other instructions, killing the tree
13703  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13704  *   instructions if the result of the load is used multiple times ?
13705  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13706  * - LAST MERGE: 108395.
13707  * - when returning vtypes in registers, generate IR and append it to the end of the
13708  *   last bb instead of doing it in the epilog.
13709  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13710  */
13711
13712 /*
13713
13714 NOTES
13715 -----
13716
13717 - When to decompose opcodes:
13718   - earlier: this makes some optimizations hard to implement, since the low level IR
13719   no longer contains the neccessary information. But it is easier to do.
13720   - later: harder to implement, enables more optimizations.
13721 - Branches inside bblocks:
13722   - created when decomposing complex opcodes. 
13723     - branches to another bblock: harmless, but not tracked by the branch 
13724       optimizations, so need to branch to a label at the start of the bblock.
13725     - branches to inside the same bblock: very problematic, trips up the local
13726       reg allocator. Can be fixed by spitting the current bblock, but that is a
13727       complex operation, since some local vregs can become global vregs etc.
13728 - Local/global vregs:
13729   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13730     local register allocator.
13731   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13732     structure, created by mono_create_var (). Assigned to hregs or the stack by
13733     the global register allocator.
13734 - When to do optimizations like alu->alu_imm:
13735   - earlier -> saves work later on since the IR will be smaller/simpler
13736   - later -> can work on more instructions
13737 - Handling of valuetypes:
13738   - When a vtype is pushed on the stack, a new temporary is created, an 
13739     instruction computing its address (LDADDR) is emitted and pushed on
13740     the stack. Need to optimize cases when the vtype is used immediately as in
13741     argument passing, stloc etc.
13742 - Instead of the to_end stuff in the old JIT, simply call the function handling
13743   the values on the stack before emitting the last instruction of the bb.
13744 */
13745
13746 #endif /* DISABLE_JIT */