Merge pull request #819 from brendanzagaeski/patch-1
[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_freg (MonoCompile *cfg)
213 {
214         return alloc_freg (cfg);
215 }
216
217 guint32
218 mono_alloc_preg (MonoCompile *cfg)
219 {
220         return alloc_preg (cfg);
221 }
222
223 guint32
224 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
225 {
226         return alloc_dreg (cfg, stack_type);
227 }
228
229 /*
230  * mono_alloc_ireg_ref:
231  *
232  *   Allocate an IREG, and mark it as holding a GC ref.
233  */
234 guint32
235 mono_alloc_ireg_ref (MonoCompile *cfg)
236 {
237         return alloc_ireg_ref (cfg);
238 }
239
240 /*
241  * mono_alloc_ireg_mp:
242  *
243  *   Allocate an IREG, and mark it as holding a managed pointer.
244  */
245 guint32
246 mono_alloc_ireg_mp (MonoCompile *cfg)
247 {
248         return alloc_ireg_mp (cfg);
249 }
250
251 /*
252  * mono_alloc_ireg_copy:
253  *
254  *   Allocate an IREG with the same GC type as VREG.
255  */
256 guint32
257 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
258 {
259         if (vreg_is_ref (cfg, vreg))
260                 return alloc_ireg_ref (cfg);
261         else if (vreg_is_mp (cfg, vreg))
262                 return alloc_ireg_mp (cfg);
263         else
264                 return alloc_ireg (cfg);
265 }
266
267 guint
268 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
269 {
270         if (type->byref)
271                 return OP_MOVE;
272
273         type = mini_replace_type (type);
274 handle_enum:
275         switch (type->type) {
276         case MONO_TYPE_I1:
277         case MONO_TYPE_U1:
278         case MONO_TYPE_BOOLEAN:
279                 return OP_MOVE;
280         case MONO_TYPE_I2:
281         case MONO_TYPE_U2:
282         case MONO_TYPE_CHAR:
283                 return OP_MOVE;
284         case MONO_TYPE_I4:
285         case MONO_TYPE_U4:
286                 return OP_MOVE;
287         case MONO_TYPE_I:
288         case MONO_TYPE_U:
289         case MONO_TYPE_PTR:
290         case MONO_TYPE_FNPTR:
291                 return OP_MOVE;
292         case MONO_TYPE_CLASS:
293         case MONO_TYPE_STRING:
294         case MONO_TYPE_OBJECT:
295         case MONO_TYPE_SZARRAY:
296         case MONO_TYPE_ARRAY:    
297                 return OP_MOVE;
298         case MONO_TYPE_I8:
299         case MONO_TYPE_U8:
300 #if SIZEOF_REGISTER == 8
301                 return OP_MOVE;
302 #else
303                 return OP_LMOVE;
304 #endif
305         case MONO_TYPE_R4:
306                 return OP_FMOVE;
307         case MONO_TYPE_R8:
308                 return OP_FMOVE;
309         case MONO_TYPE_VALUETYPE:
310                 if (type->data.klass->enumtype) {
311                         type = mono_class_enum_basetype (type->data.klass);
312                         goto handle_enum;
313                 }
314                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
315                         return OP_XMOVE;
316                 return OP_VMOVE;
317         case MONO_TYPE_TYPEDBYREF:
318                 return OP_VMOVE;
319         case MONO_TYPE_GENERICINST:
320                 type = &type->data.generic_class->container_class->byval_arg;
321                 goto handle_enum;
322         case MONO_TYPE_VAR:
323         case MONO_TYPE_MVAR:
324                 g_assert (cfg->generic_sharing_context);
325                 if (mini_type_var_is_vt (cfg, type))
326                         return OP_VMOVE;
327                 else
328                         return OP_MOVE;
329         default:
330                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
331         }
332         return -1;
333 }
334
335 void
336 mono_print_bb (MonoBasicBlock *bb, const char *msg)
337 {
338         int i;
339         MonoInst *tree;
340
341         printf ("\n%s %d: [IN: ", msg, bb->block_num);
342         for (i = 0; i < bb->in_count; ++i)
343                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
344         printf (", OUT: ");
345         for (i = 0; i < bb->out_count; ++i)
346                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
347         printf (" ]\n");
348         for (tree = bb->code; tree; tree = tree->next)
349                 mono_print_ins_index (-1, tree);
350 }
351
352 void
353 mono_create_helper_signatures (void)
354 {
355         helper_sig_domain_get = mono_create_icall_signature ("ptr");
356         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
357         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
358         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
359         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
360         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
361         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
362 }
363
364 /*
365  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
366  * foo<T> (int i) { ldarg.0; box T; }
367  */
368 #define UNVERIFIED do { \
369         if (cfg->gsharedvt) { \
370                 if (cfg->verbose_level > 2)                                                                     \
371                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
372                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
373                 goto exception_exit;                                                                                    \
374         }                                                                                                                                       \
375         if (mini_get_debug_options ()->break_on_unverified) \
376                 G_BREAKPOINT (); \
377         else \
378                 goto unverified; \
379 } while (0)
380
381 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
382
383 #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)
384
385 #define GET_BBLOCK(cfg,tblock,ip) do {  \
386                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
387                 if (!(tblock)) {        \
388                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
389             NEW_BBLOCK (cfg, (tblock)); \
390                         (tblock)->cil_code = (ip);      \
391                         ADD_BBLOCK (cfg, (tblock));     \
392                 } \
393         } while (0)
394
395 #if defined(TARGET_X86) || defined(TARGET_AMD64)
396 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
397                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
398                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
399                 (dest)->sreg1 = (sr1); \
400                 (dest)->sreg2 = (sr2); \
401                 (dest)->inst_imm = (imm); \
402                 (dest)->backend.shift_amount = (shift); \
403                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
404         } while (0)
405 #endif
406
407 #if SIZEOF_REGISTER == 8
408 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
409                 /* FIXME: Need to add many more cases */ \
410                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
411                         MonoInst *widen; \
412                         int dr = alloc_preg (cfg); \
413                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
414                         (ins)->sreg2 = widen->dreg; \
415                 } \
416         } while (0)
417 #else
418 #define ADD_WIDEN_OP(ins, arg1, arg2)
419 #endif
420
421 #define ADD_BINOP(op) do {      \
422                 MONO_INST_NEW (cfg, ins, (op)); \
423                 sp -= 2;        \
424                 ins->sreg1 = sp [0]->dreg;      \
425                 ins->sreg2 = sp [1]->dreg;      \
426                 type_from_op (ins, sp [0], sp [1]);     \
427                 CHECK_TYPE (ins);       \
428                 /* Have to insert a widening op */               \
429         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
430         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
431         MONO_ADD_INS ((cfg)->cbb, (ins)); \
432         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
433         } while (0)
434
435 #define ADD_UNOP(op) do {       \
436                 MONO_INST_NEW (cfg, ins, (op)); \
437                 sp--;   \
438                 ins->sreg1 = sp [0]->dreg;      \
439                 type_from_op (ins, sp [0], NULL);       \
440                 CHECK_TYPE (ins);       \
441         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
442         MONO_ADD_INS ((cfg)->cbb, (ins)); \
443                 *sp++ = mono_decompose_opcode (cfg, ins); \
444         } while (0)
445
446 #define ADD_BINCOND(next_block) do {    \
447                 MonoInst *cmp;  \
448                 sp -= 2; \
449                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
450                 cmp->sreg1 = sp [0]->dreg;      \
451                 cmp->sreg2 = sp [1]->dreg;      \
452                 type_from_op (cmp, sp [0], sp [1]);     \
453                 CHECK_TYPE (cmp);       \
454                 type_from_op (ins, sp [0], sp [1]);     \
455                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
456                 GET_BBLOCK (cfg, tblock, target);               \
457                 link_bblock (cfg, bblock, tblock);      \
458                 ins->inst_true_bb = tblock;     \
459                 if ((next_block)) {     \
460                         link_bblock (cfg, bblock, (next_block));        \
461                         ins->inst_false_bb = (next_block);      \
462                         start_new_bblock = 1;   \
463                 } else {        \
464                         GET_BBLOCK (cfg, tblock, ip);           \
465                         link_bblock (cfg, bblock, tblock);      \
466                         ins->inst_false_bb = tblock;    \
467                         start_new_bblock = 2;   \
468                 }       \
469                 if (sp != stack_start) {                                                                        \
470                     handle_stack_args (cfg, stack_start, sp - stack_start); \
471                         CHECK_UNVERIFIABLE (cfg); \
472                 } \
473         MONO_ADD_INS (bblock, cmp); \
474                 MONO_ADD_INS (bblock, ins);     \
475         } while (0)
476
477 /* *
478  * link_bblock: Links two basic blocks
479  *
480  * links two basic blocks in the control flow graph, the 'from'
481  * argument is the starting block and the 'to' argument is the block
482  * the control flow ends to after 'from'.
483  */
484 static void
485 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
486 {
487         MonoBasicBlock **newa;
488         int i, found;
489
490 #if 0
491         if (from->cil_code) {
492                 if (to->cil_code)
493                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
494                 else
495                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
496         } else {
497                 if (to->cil_code)
498                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
499                 else
500                         printf ("edge from entry to exit\n");
501         }
502 #endif
503
504         found = FALSE;
505         for (i = 0; i < from->out_count; ++i) {
506                 if (to == from->out_bb [i]) {
507                         found = TRUE;
508                         break;
509                 }
510         }
511         if (!found) {
512                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
513                 for (i = 0; i < from->out_count; ++i) {
514                         newa [i] = from->out_bb [i];
515                 }
516                 newa [i] = to;
517                 from->out_count++;
518                 from->out_bb = newa;
519         }
520
521         found = FALSE;
522         for (i = 0; i < to->in_count; ++i) {
523                 if (from == to->in_bb [i]) {
524                         found = TRUE;
525                         break;
526                 }
527         }
528         if (!found) {
529                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
530                 for (i = 0; i < to->in_count; ++i) {
531                         newa [i] = to->in_bb [i];
532                 }
533                 newa [i] = from;
534                 to->in_count++;
535                 to->in_bb = newa;
536         }
537 }
538
539 void
540 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
541 {
542         link_bblock (cfg, from, to);
543 }
544
545 /**
546  * mono_find_block_region:
547  *
548  *   We mark each basic block with a region ID. We use that to avoid BB
549  *   optimizations when blocks are in different regions.
550  *
551  * Returns:
552  *   A region token that encodes where this region is, and information
553  *   about the clause owner for this block.
554  *
555  *   The region encodes the try/catch/filter clause that owns this block
556  *   as well as the type.  -1 is a special value that represents a block
557  *   that is in none of try/catch/filter.
558  */
559 static int
560 mono_find_block_region (MonoCompile *cfg, int offset)
561 {
562         MonoMethodHeader *header = cfg->header;
563         MonoExceptionClause *clause;
564         int i;
565
566         for (i = 0; i < header->num_clauses; ++i) {
567                 clause = &header->clauses [i];
568                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
569                     (offset < (clause->handler_offset)))
570                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
571                            
572                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
573                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
574                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
575                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
576                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
577                         else
578                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
579                 }
580
581                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
582                         return ((i + 1) << 8) | clause->flags;
583         }
584
585         return -1;
586 }
587
588 static GList*
589 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
590 {
591         MonoMethodHeader *header = cfg->header;
592         MonoExceptionClause *clause;
593         int i;
594         GList *res = NULL;
595
596         for (i = 0; i < header->num_clauses; ++i) {
597                 clause = &header->clauses [i];
598                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
599                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
600                         if (clause->flags == type)
601                                 res = g_list_append (res, clause);
602                 }
603         }
604         return res;
605 }
606
607 static void
608 mono_create_spvar_for_region (MonoCompile *cfg, int region)
609 {
610         MonoInst *var;
611
612         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
613         if (var)
614                 return;
615
616         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
617         /* prevent it from being register allocated */
618         var->flags |= MONO_INST_VOLATILE;
619
620         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
621 }
622
623 MonoInst *
624 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
625 {
626         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
627 }
628
629 static MonoInst*
630 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
631 {
632         MonoInst *var;
633
634         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
635         if (var)
636                 return var;
637
638         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
639         /* prevent it from being register allocated */
640         var->flags |= MONO_INST_VOLATILE;
641
642         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
643
644         return var;
645 }
646
647 /*
648  * Returns the type used in the eval stack when @type is loaded.
649  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
650  */
651 void
652 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
653 {
654         MonoClass *klass;
655
656         type = mini_replace_type (type);
657         inst->klass = klass = mono_class_from_mono_type (type);
658         if (type->byref) {
659                 inst->type = STACK_MP;
660                 return;
661         }
662
663 handle_enum:
664         switch (type->type) {
665         case MONO_TYPE_VOID:
666                 inst->type = STACK_INV;
667                 return;
668         case MONO_TYPE_I1:
669         case MONO_TYPE_U1:
670         case MONO_TYPE_BOOLEAN:
671         case MONO_TYPE_I2:
672         case MONO_TYPE_U2:
673         case MONO_TYPE_CHAR:
674         case MONO_TYPE_I4:
675         case MONO_TYPE_U4:
676                 inst->type = STACK_I4;
677                 return;
678         case MONO_TYPE_I:
679         case MONO_TYPE_U:
680         case MONO_TYPE_PTR:
681         case MONO_TYPE_FNPTR:
682                 inst->type = STACK_PTR;
683                 return;
684         case MONO_TYPE_CLASS:
685         case MONO_TYPE_STRING:
686         case MONO_TYPE_OBJECT:
687         case MONO_TYPE_SZARRAY:
688         case MONO_TYPE_ARRAY:    
689                 inst->type = STACK_OBJ;
690                 return;
691         case MONO_TYPE_I8:
692         case MONO_TYPE_U8:
693                 inst->type = STACK_I8;
694                 return;
695         case MONO_TYPE_R4:
696         case MONO_TYPE_R8:
697                 inst->type = STACK_R8;
698                 return;
699         case MONO_TYPE_VALUETYPE:
700                 if (type->data.klass->enumtype) {
701                         type = mono_class_enum_basetype (type->data.klass);
702                         goto handle_enum;
703                 } else {
704                         inst->klass = klass;
705                         inst->type = STACK_VTYPE;
706                         return;
707                 }
708         case MONO_TYPE_TYPEDBYREF:
709                 inst->klass = mono_defaults.typed_reference_class;
710                 inst->type = STACK_VTYPE;
711                 return;
712         case MONO_TYPE_GENERICINST:
713                 type = &type->data.generic_class->container_class->byval_arg;
714                 goto handle_enum;
715         case MONO_TYPE_VAR:
716         case MONO_TYPE_MVAR:
717                 g_assert (cfg->generic_sharing_context);
718                 if (mini_is_gsharedvt_type (cfg, type)) {
719                         g_assert (cfg->gsharedvt);
720                         inst->type = STACK_VTYPE;
721                 } else {
722                         inst->type = STACK_OBJ;
723                 }
724                 return;
725         default:
726                 g_error ("unknown type 0x%02x in eval stack type", type->type);
727         }
728 }
729
730 /*
731  * The following tables are used to quickly validate the IL code in type_from_op ().
732  */
733 static const char
734 bin_num_table [STACK_MAX] [STACK_MAX] = {
735         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
736         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
737         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
738         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
739         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
740         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
741         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
742         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
743 };
744
745 static const char 
746 neg_table [] = {
747         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
748 };
749
750 /* reduce the size of this table */
751 static const char
752 bin_int_table [STACK_MAX] [STACK_MAX] = {
753         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
754         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
755         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
756         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
757         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
758         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
759         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
760         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
761 };
762
763 static const char
764 bin_comp_table [STACK_MAX] [STACK_MAX] = {
765 /*      Inv i  L  p  F  &  O  vt */
766         {0},
767         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
768         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
769         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
770         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
771         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
772         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
773         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
774 };
775
776 /* reduce the size of this table */
777 static const char
778 shift_table [STACK_MAX] [STACK_MAX] = {
779         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
780         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
781         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
782         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
783         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
784         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
785         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
786         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
787 };
788
789 /*
790  * Tables to map from the non-specific opcode to the matching
791  * type-specific opcode.
792  */
793 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
794 static const guint16
795 binops_op_map [STACK_MAX] = {
796         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
797 };
798
799 /* handles from CEE_NEG to CEE_CONV_U8 */
800 static const guint16
801 unops_op_map [STACK_MAX] = {
802         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
803 };
804
805 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
806 static const guint16
807 ovfops_op_map [STACK_MAX] = {
808         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
809 };
810
811 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
812 static const guint16
813 ovf2ops_op_map [STACK_MAX] = {
814         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
815 };
816
817 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
818 static const guint16
819 ovf3ops_op_map [STACK_MAX] = {
820         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
821 };
822
823 /* handles from CEE_BEQ to CEE_BLT_UN */
824 static const guint16
825 beqops_op_map [STACK_MAX] = {
826         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
827 };
828
829 /* handles from CEE_CEQ to CEE_CLT_UN */
830 static const guint16
831 ceqops_op_map [STACK_MAX] = {
832         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
833 };
834
835 /*
836  * Sets ins->type (the type on the eval stack) according to the
837  * type of the opcode and the arguments to it.
838  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
839  *
840  * FIXME: this function sets ins->type unconditionally in some cases, but
841  * it should set it to invalid for some types (a conv.x on an object)
842  */
843 static void
844 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
845
846         switch (ins->opcode) {
847         /* binops */
848         case CEE_ADD:
849         case CEE_SUB:
850         case CEE_MUL:
851         case CEE_DIV:
852         case CEE_REM:
853                 /* FIXME: check unverifiable args for STACK_MP */
854                 ins->type = bin_num_table [src1->type] [src2->type];
855                 ins->opcode += binops_op_map [ins->type];
856                 break;
857         case CEE_DIV_UN:
858         case CEE_REM_UN:
859         case CEE_AND:
860         case CEE_OR:
861         case CEE_XOR:
862                 ins->type = bin_int_table [src1->type] [src2->type];
863                 ins->opcode += binops_op_map [ins->type];
864                 break;
865         case CEE_SHL:
866         case CEE_SHR:
867         case CEE_SHR_UN:
868                 ins->type = shift_table [src1->type] [src2->type];
869                 ins->opcode += binops_op_map [ins->type];
870                 break;
871         case OP_COMPARE:
872         case OP_LCOMPARE:
873         case OP_ICOMPARE:
874                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
875                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
876                         ins->opcode = OP_LCOMPARE;
877                 else if (src1->type == STACK_R8)
878                         ins->opcode = OP_FCOMPARE;
879                 else
880                         ins->opcode = OP_ICOMPARE;
881                 break;
882         case OP_ICOMPARE_IMM:
883                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
884                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
885                         ins->opcode = OP_LCOMPARE_IMM;          
886                 break;
887         case CEE_BEQ:
888         case CEE_BGE:
889         case CEE_BGT:
890         case CEE_BLE:
891         case CEE_BLT:
892         case CEE_BNE_UN:
893         case CEE_BGE_UN:
894         case CEE_BGT_UN:
895         case CEE_BLE_UN:
896         case CEE_BLT_UN:
897                 ins->opcode += beqops_op_map [src1->type];
898                 break;
899         case OP_CEQ:
900                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
901                 ins->opcode += ceqops_op_map [src1->type];
902                 break;
903         case OP_CGT:
904         case OP_CGT_UN:
905         case OP_CLT:
906         case OP_CLT_UN:
907                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
908                 ins->opcode += ceqops_op_map [src1->type];
909                 break;
910         /* unops */
911         case CEE_NEG:
912                 ins->type = neg_table [src1->type];
913                 ins->opcode += unops_op_map [ins->type];
914                 break;
915         case CEE_NOT:
916                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
917                         ins->type = src1->type;
918                 else
919                         ins->type = STACK_INV;
920                 ins->opcode += unops_op_map [ins->type];
921                 break;
922         case CEE_CONV_I1:
923         case CEE_CONV_I2:
924         case CEE_CONV_I4:
925         case CEE_CONV_U4:
926                 ins->type = STACK_I4;
927                 ins->opcode += unops_op_map [src1->type];
928                 break;
929         case CEE_CONV_R_UN:
930                 ins->type = STACK_R8;
931                 switch (src1->type) {
932                 case STACK_I4:
933                 case STACK_PTR:
934                         ins->opcode = OP_ICONV_TO_R_UN;
935                         break;
936                 case STACK_I8:
937                         ins->opcode = OP_LCONV_TO_R_UN; 
938                         break;
939                 }
940                 break;
941         case CEE_CONV_OVF_I1:
942         case CEE_CONV_OVF_U1:
943         case CEE_CONV_OVF_I2:
944         case CEE_CONV_OVF_U2:
945         case CEE_CONV_OVF_I4:
946         case CEE_CONV_OVF_U4:
947                 ins->type = STACK_I4;
948                 ins->opcode += ovf3ops_op_map [src1->type];
949                 break;
950         case CEE_CONV_OVF_I_UN:
951         case CEE_CONV_OVF_U_UN:
952                 ins->type = STACK_PTR;
953                 ins->opcode += ovf2ops_op_map [src1->type];
954                 break;
955         case CEE_CONV_OVF_I1_UN:
956         case CEE_CONV_OVF_I2_UN:
957         case CEE_CONV_OVF_I4_UN:
958         case CEE_CONV_OVF_U1_UN:
959         case CEE_CONV_OVF_U2_UN:
960         case CEE_CONV_OVF_U4_UN:
961                 ins->type = STACK_I4;
962                 ins->opcode += ovf2ops_op_map [src1->type];
963                 break;
964         case CEE_CONV_U:
965                 ins->type = STACK_PTR;
966                 switch (src1->type) {
967                 case STACK_I4:
968                         ins->opcode = OP_ICONV_TO_U;
969                         break;
970                 case STACK_PTR:
971                 case STACK_MP:
972 #if SIZEOF_VOID_P == 8
973                         ins->opcode = OP_LCONV_TO_U;
974 #else
975                         ins->opcode = OP_MOVE;
976 #endif
977                         break;
978                 case STACK_I8:
979                         ins->opcode = OP_LCONV_TO_U;
980                         break;
981                 case STACK_R8:
982                         ins->opcode = OP_FCONV_TO_U;
983                         break;
984                 }
985                 break;
986         case CEE_CONV_I8:
987         case CEE_CONV_U8:
988                 ins->type = STACK_I8;
989                 ins->opcode += unops_op_map [src1->type];
990                 break;
991         case CEE_CONV_OVF_I8:
992         case CEE_CONV_OVF_U8:
993                 ins->type = STACK_I8;
994                 ins->opcode += ovf3ops_op_map [src1->type];
995                 break;
996         case CEE_CONV_OVF_U8_UN:
997         case CEE_CONV_OVF_I8_UN:
998                 ins->type = STACK_I8;
999                 ins->opcode += ovf2ops_op_map [src1->type];
1000                 break;
1001         case CEE_CONV_R4:
1002         case CEE_CONV_R8:
1003                 ins->type = STACK_R8;
1004                 ins->opcode += unops_op_map [src1->type];
1005                 break;
1006         case OP_CKFINITE:
1007                 ins->type = STACK_R8;           
1008                 break;
1009         case CEE_CONV_U2:
1010         case CEE_CONV_U1:
1011                 ins->type = STACK_I4;
1012                 ins->opcode += ovfops_op_map [src1->type];
1013                 break;
1014         case CEE_CONV_I:
1015         case CEE_CONV_OVF_I:
1016         case CEE_CONV_OVF_U:
1017                 ins->type = STACK_PTR;
1018                 ins->opcode += ovfops_op_map [src1->type];
1019                 break;
1020         case CEE_ADD_OVF:
1021         case CEE_ADD_OVF_UN:
1022         case CEE_MUL_OVF:
1023         case CEE_MUL_OVF_UN:
1024         case CEE_SUB_OVF:
1025         case CEE_SUB_OVF_UN:
1026                 ins->type = bin_num_table [src1->type] [src2->type];
1027                 ins->opcode += ovfops_op_map [src1->type];
1028                 if (ins->type == STACK_R8)
1029                         ins->type = STACK_INV;
1030                 break;
1031         case OP_LOAD_MEMBASE:
1032                 ins->type = STACK_PTR;
1033                 break;
1034         case OP_LOADI1_MEMBASE:
1035         case OP_LOADU1_MEMBASE:
1036         case OP_LOADI2_MEMBASE:
1037         case OP_LOADU2_MEMBASE:
1038         case OP_LOADI4_MEMBASE:
1039         case OP_LOADU4_MEMBASE:
1040                 ins->type = STACK_PTR;
1041                 break;
1042         case OP_LOADI8_MEMBASE:
1043                 ins->type = STACK_I8;
1044                 break;
1045         case OP_LOADR4_MEMBASE:
1046         case OP_LOADR8_MEMBASE:
1047                 ins->type = STACK_R8;
1048                 break;
1049         default:
1050                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1051                 break;
1052         }
1053
1054         if (ins->type == STACK_MP)
1055                 ins->klass = mono_defaults.object_class;
1056 }
1057
1058 static const char 
1059 ldind_type [] = {
1060         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1061 };
1062
1063 #if 0
1064
1065 static const char
1066 param_table [STACK_MAX] [STACK_MAX] = {
1067         {0},
1068 };
1069
1070 static int
1071 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1072         int i;
1073
1074         if (sig->hasthis) {
1075                 switch (args->type) {
1076                 case STACK_I4:
1077                 case STACK_I8:
1078                 case STACK_R8:
1079                 case STACK_VTYPE:
1080                 case STACK_INV:
1081                         return 0;
1082                 }
1083                 args++;
1084         }
1085         for (i = 0; i < sig->param_count; ++i) {
1086                 switch (args [i].type) {
1087                 case STACK_INV:
1088                         return 0;
1089                 case STACK_MP:
1090                         if (!sig->params [i]->byref)
1091                                 return 0;
1092                         continue;
1093                 case STACK_OBJ:
1094                         if (sig->params [i]->byref)
1095                                 return 0;
1096                         switch (sig->params [i]->type) {
1097                         case MONO_TYPE_CLASS:
1098                         case MONO_TYPE_STRING:
1099                         case MONO_TYPE_OBJECT:
1100                         case MONO_TYPE_SZARRAY:
1101                         case MONO_TYPE_ARRAY:
1102                                 break;
1103                         default:
1104                                 return 0;
1105                         }
1106                         continue;
1107                 case STACK_R8:
1108                         if (sig->params [i]->byref)
1109                                 return 0;
1110                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1111                                 return 0;
1112                         continue;
1113                 case STACK_PTR:
1114                 case STACK_I4:
1115                 case STACK_I8:
1116                 case STACK_VTYPE:
1117                         break;
1118                 }
1119                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1120                         return 0;*/
1121         }
1122         return 1;
1123 }
1124 #endif
1125
1126 /*
1127  * When we need a pointer to the current domain many times in a method, we
1128  * call mono_domain_get() once and we store the result in a local variable.
1129  * This function returns the variable that represents the MonoDomain*.
1130  */
1131 inline static MonoInst *
1132 mono_get_domainvar (MonoCompile *cfg)
1133 {
1134         if (!cfg->domainvar)
1135                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1136         return cfg->domainvar;
1137 }
1138
1139 /*
1140  * The got_var contains the address of the Global Offset Table when AOT 
1141  * compiling.
1142  */
1143 MonoInst *
1144 mono_get_got_var (MonoCompile *cfg)
1145 {
1146 #ifdef MONO_ARCH_NEED_GOT_VAR
1147         if (!cfg->compile_aot)
1148                 return NULL;
1149         if (!cfg->got_var) {
1150                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1151         }
1152         return cfg->got_var;
1153 #else
1154         return NULL;
1155 #endif
1156 }
1157
1158 static MonoInst *
1159 mono_get_vtable_var (MonoCompile *cfg)
1160 {
1161         g_assert (cfg->generic_sharing_context);
1162
1163         if (!cfg->rgctx_var) {
1164                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1165                 /* force the var to be stack allocated */
1166                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1167         }
1168
1169         return cfg->rgctx_var;
1170 }
1171
1172 static MonoType*
1173 type_from_stack_type (MonoInst *ins) {
1174         switch (ins->type) {
1175         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1176         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1177         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1178         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1179         case STACK_MP:
1180                 return &ins->klass->this_arg;
1181         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1182         case STACK_VTYPE: return &ins->klass->byval_arg;
1183         default:
1184                 g_error ("stack type %d to monotype not handled\n", ins->type);
1185         }
1186         return NULL;
1187 }
1188
1189 static G_GNUC_UNUSED int
1190 type_to_stack_type (MonoType *t)
1191 {
1192         t = mono_type_get_underlying_type (t);
1193         switch (t->type) {
1194         case MONO_TYPE_I1:
1195         case MONO_TYPE_U1:
1196         case MONO_TYPE_BOOLEAN:
1197         case MONO_TYPE_I2:
1198         case MONO_TYPE_U2:
1199         case MONO_TYPE_CHAR:
1200         case MONO_TYPE_I4:
1201         case MONO_TYPE_U4:
1202                 return STACK_I4;
1203         case MONO_TYPE_I:
1204         case MONO_TYPE_U:
1205         case MONO_TYPE_PTR:
1206         case MONO_TYPE_FNPTR:
1207                 return STACK_PTR;
1208         case MONO_TYPE_CLASS:
1209         case MONO_TYPE_STRING:
1210         case MONO_TYPE_OBJECT:
1211         case MONO_TYPE_SZARRAY:
1212         case MONO_TYPE_ARRAY:    
1213                 return STACK_OBJ;
1214         case MONO_TYPE_I8:
1215         case MONO_TYPE_U8:
1216                 return STACK_I8;
1217         case MONO_TYPE_R4:
1218         case MONO_TYPE_R8:
1219                 return STACK_R8;
1220         case MONO_TYPE_VALUETYPE:
1221         case MONO_TYPE_TYPEDBYREF:
1222                 return STACK_VTYPE;
1223         case MONO_TYPE_GENERICINST:
1224                 if (mono_type_generic_inst_is_valuetype (t))
1225                         return STACK_VTYPE;
1226                 else
1227                         return STACK_OBJ;
1228                 break;
1229         default:
1230                 g_assert_not_reached ();
1231         }
1232
1233         return -1;
1234 }
1235
1236 static MonoClass*
1237 array_access_to_klass (int opcode)
1238 {
1239         switch (opcode) {
1240         case CEE_LDELEM_U1:
1241                 return mono_defaults.byte_class;
1242         case CEE_LDELEM_U2:
1243                 return mono_defaults.uint16_class;
1244         case CEE_LDELEM_I:
1245         case CEE_STELEM_I:
1246                 return mono_defaults.int_class;
1247         case CEE_LDELEM_I1:
1248         case CEE_STELEM_I1:
1249                 return mono_defaults.sbyte_class;
1250         case CEE_LDELEM_I2:
1251         case CEE_STELEM_I2:
1252                 return mono_defaults.int16_class;
1253         case CEE_LDELEM_I4:
1254         case CEE_STELEM_I4:
1255                 return mono_defaults.int32_class;
1256         case CEE_LDELEM_U4:
1257                 return mono_defaults.uint32_class;
1258         case CEE_LDELEM_I8:
1259         case CEE_STELEM_I8:
1260                 return mono_defaults.int64_class;
1261         case CEE_LDELEM_R4:
1262         case CEE_STELEM_R4:
1263                 return mono_defaults.single_class;
1264         case CEE_LDELEM_R8:
1265         case CEE_STELEM_R8:
1266                 return mono_defaults.double_class;
1267         case CEE_LDELEM_REF:
1268         case CEE_STELEM_REF:
1269                 return mono_defaults.object_class;
1270         default:
1271                 g_assert_not_reached ();
1272         }
1273         return NULL;
1274 }
1275
1276 /*
1277  * We try to share variables when possible
1278  */
1279 static MonoInst *
1280 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1281 {
1282         MonoInst *res;
1283         int pos, vnum;
1284
1285         /* inlining can result in deeper stacks */ 
1286         if (slot >= cfg->header->max_stack)
1287                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1288
1289         pos = ins->type - 1 + slot * STACK_MAX;
1290
1291         switch (ins->type) {
1292         case STACK_I4:
1293         case STACK_I8:
1294         case STACK_R8:
1295         case STACK_PTR:
1296         case STACK_MP:
1297         case STACK_OBJ:
1298                 if ((vnum = cfg->intvars [pos]))
1299                         return cfg->varinfo [vnum];
1300                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1301                 cfg->intvars [pos] = res->inst_c0;
1302                 break;
1303         default:
1304                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1305         }
1306         return res;
1307 }
1308
1309 static void
1310 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1311 {
1312         /* 
1313          * Don't use this if a generic_context is set, since that means AOT can't
1314          * look up the method using just the image+token.
1315          * table == 0 means this is a reference made from a wrapper.
1316          */
1317         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1318                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1319                 jump_info_token->image = image;
1320                 jump_info_token->token = token;
1321                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1322         }
1323 }
1324
1325 /*
1326  * This function is called to handle items that are left on the evaluation stack
1327  * at basic block boundaries. What happens is that we save the values to local variables
1328  * and we reload them later when first entering the target basic block (with the
1329  * handle_loaded_temps () function).
1330  * A single joint point will use the same variables (stored in the array bb->out_stack or
1331  * bb->in_stack, if the basic block is before or after the joint point).
1332  *
1333  * This function needs to be called _before_ emitting the last instruction of
1334  * the bb (i.e. before emitting a branch).
1335  * If the stack merge fails at a join point, cfg->unverifiable is set.
1336  */
1337 static void
1338 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1339 {
1340         int i, bindex;
1341         MonoBasicBlock *bb = cfg->cbb;
1342         MonoBasicBlock *outb;
1343         MonoInst *inst, **locals;
1344         gboolean found;
1345
1346         if (!count)
1347                 return;
1348         if (cfg->verbose_level > 3)
1349                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1350         if (!bb->out_scount) {
1351                 bb->out_scount = count;
1352                 //printf ("bblock %d has out:", bb->block_num);
1353                 found = FALSE;
1354                 for (i = 0; i < bb->out_count; ++i) {
1355                         outb = bb->out_bb [i];
1356                         /* exception handlers are linked, but they should not be considered for stack args */
1357                         if (outb->flags & BB_EXCEPTION_HANDLER)
1358                                 continue;
1359                         //printf (" %d", outb->block_num);
1360                         if (outb->in_stack) {
1361                                 found = TRUE;
1362                                 bb->out_stack = outb->in_stack;
1363                                 break;
1364                         }
1365                 }
1366                 //printf ("\n");
1367                 if (!found) {
1368                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1369                         for (i = 0; i < count; ++i) {
1370                                 /* 
1371                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1372                                  * stack slot and if they are of the same type.
1373                                  * This won't cause conflicts since if 'local' is used to 
1374                                  * store one of the values in the in_stack of a bblock, then
1375                                  * the same variable will be used for the same outgoing stack 
1376                                  * slot as well. 
1377                                  * This doesn't work when inlining methods, since the bblocks
1378                                  * in the inlined methods do not inherit their in_stack from
1379                                  * the bblock they are inlined to. See bug #58863 for an
1380                                  * example.
1381                                  */
1382                                 if (cfg->inlined_method)
1383                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1384                                 else
1385                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1386                         }
1387                 }
1388         }
1389
1390         for (i = 0; i < bb->out_count; ++i) {
1391                 outb = bb->out_bb [i];
1392                 /* exception handlers are linked, but they should not be considered for stack args */
1393                 if (outb->flags & BB_EXCEPTION_HANDLER)
1394                         continue;
1395                 if (outb->in_scount) {
1396                         if (outb->in_scount != bb->out_scount) {
1397                                 cfg->unverifiable = TRUE;
1398                                 return;
1399                         }
1400                         continue; /* check they are the same locals */
1401                 }
1402                 outb->in_scount = count;
1403                 outb->in_stack = bb->out_stack;
1404         }
1405
1406         locals = bb->out_stack;
1407         cfg->cbb = bb;
1408         for (i = 0; i < count; ++i) {
1409                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1410                 inst->cil_code = sp [i]->cil_code;
1411                 sp [i] = locals [i];
1412                 if (cfg->verbose_level > 3)
1413                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1414         }
1415
1416         /*
1417          * It is possible that the out bblocks already have in_stack assigned, and
1418          * the in_stacks differ. In this case, we will store to all the different 
1419          * in_stacks.
1420          */
1421
1422         found = TRUE;
1423         bindex = 0;
1424         while (found) {
1425                 /* Find a bblock which has a different in_stack */
1426                 found = FALSE;
1427                 while (bindex < bb->out_count) {
1428                         outb = bb->out_bb [bindex];
1429                         /* exception handlers are linked, but they should not be considered for stack args */
1430                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1431                                 bindex++;
1432                                 continue;
1433                         }
1434                         if (outb->in_stack != locals) {
1435                                 for (i = 0; i < count; ++i) {
1436                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1437                                         inst->cil_code = sp [i]->cil_code;
1438                                         sp [i] = locals [i];
1439                                         if (cfg->verbose_level > 3)
1440                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1441                                 }
1442                                 locals = outb->in_stack;
1443                                 found = TRUE;
1444                                 break;
1445                         }
1446                         bindex ++;
1447                 }
1448         }
1449 }
1450
1451 /* Emit code which loads interface_offsets [klass->interface_id]
1452  * The array is stored in memory before vtable.
1453 */
1454 static void
1455 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1456 {
1457         if (cfg->compile_aot) {
1458                 int ioffset_reg = alloc_preg (cfg);
1459                 int iid_reg = alloc_preg (cfg);
1460
1461                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1462                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1463                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1464         }
1465         else {
1466                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1467         }
1468 }
1469
1470 static void
1471 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1472 {
1473         int ibitmap_reg = alloc_preg (cfg);
1474 #ifdef COMPRESSED_INTERFACE_BITMAP
1475         MonoInst *args [2];
1476         MonoInst *res, *ins;
1477         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1478         MONO_ADD_INS (cfg->cbb, ins);
1479         args [0] = ins;
1480         if (cfg->compile_aot)
1481                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1482         else
1483                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1484         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1485         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1486 #else
1487         int ibitmap_byte_reg = alloc_preg (cfg);
1488
1489         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1490
1491         if (cfg->compile_aot) {
1492                 int iid_reg = alloc_preg (cfg);
1493                 int shifted_iid_reg = alloc_preg (cfg);
1494                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1495                 int masked_iid_reg = alloc_preg (cfg);
1496                 int iid_one_bit_reg = alloc_preg (cfg);
1497                 int iid_bit_reg = alloc_preg (cfg);
1498                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1499                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1500                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1501                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1502                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1503                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1504                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1505                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1506         } else {
1507                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1508                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1509         }
1510 #endif
1511 }
1512
1513 /* 
1514  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1515  * stored in "klass_reg" implements the interface "klass".
1516  */
1517 static void
1518 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1519 {
1520         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1521 }
1522
1523 /* 
1524  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1525  * stored in "vtable_reg" implements the interface "klass".
1526  */
1527 static void
1528 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1529 {
1530         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1531 }
1532
1533 /* 
1534  * Emit code which checks whenever the interface id of @klass is smaller than
1535  * than the value given by max_iid_reg.
1536 */
1537 static void
1538 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1539                                                  MonoBasicBlock *false_target)
1540 {
1541         if (cfg->compile_aot) {
1542                 int iid_reg = alloc_preg (cfg);
1543                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1544                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1545         }
1546         else
1547                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1548         if (false_target)
1549                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1550         else
1551                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1552 }
1553
1554 /* Same as above, but obtains max_iid from a vtable */
1555 static void
1556 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1557                                                                  MonoBasicBlock *false_target)
1558 {
1559         int max_iid_reg = alloc_preg (cfg);
1560                 
1561         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1562         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1563 }
1564
1565 /* Same as above, but obtains max_iid from a klass */
1566 static void
1567 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1568                                                                  MonoBasicBlock *false_target)
1569 {
1570         int max_iid_reg = alloc_preg (cfg);
1571
1572         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1573         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1574 }
1575
1576 static void
1577 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1578 {
1579         int idepth_reg = alloc_preg (cfg);
1580         int stypes_reg = alloc_preg (cfg);
1581         int stype = alloc_preg (cfg);
1582
1583         mono_class_setup_supertypes (klass);
1584
1585         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1586                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1587                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1588                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1589         }
1590         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1591         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1592         if (klass_ins) {
1593                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1594         } else if (cfg->compile_aot) {
1595                 int const_reg = alloc_preg (cfg);
1596                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1597                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1598         } else {
1599                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1600         }
1601         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1602 }
1603
1604 static void
1605 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1606 {
1607         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1608 }
1609
1610 static void
1611 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1612 {
1613         int intf_reg = alloc_preg (cfg);
1614
1615         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1616         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1617         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1618         if (true_target)
1619                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1620         else
1621                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1622 }
1623
1624 /*
1625  * Variant of the above that takes a register to the class, not the vtable.
1626  */
1627 static void
1628 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1629 {
1630         int intf_bit_reg = alloc_preg (cfg);
1631
1632         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1633         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1634         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1635         if (true_target)
1636                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1637         else
1638                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1639 }
1640
1641 static inline void
1642 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1643 {
1644         if (klass_inst) {
1645                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1646         } else if (cfg->compile_aot) {
1647                 int const_reg = alloc_preg (cfg);
1648                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1649                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1650         } else {
1651                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1652         }
1653         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1654 }
1655
1656 static inline void
1657 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1658 {
1659         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1660 }
1661
1662 static inline void
1663 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1664 {
1665         if (cfg->compile_aot) {
1666                 int const_reg = alloc_preg (cfg);
1667                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1668                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1669         } else {
1670                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1671         }
1672         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1673 }
1674
1675 static void
1676 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1677         
1678 static void
1679 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1680 {
1681         if (klass->rank) {
1682                 int rank_reg = alloc_preg (cfg);
1683                 int eclass_reg = alloc_preg (cfg);
1684
1685                 g_assert (!klass_inst);
1686                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1687                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1688                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1689                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1690                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1691                 if (klass->cast_class == mono_defaults.object_class) {
1692                         int parent_reg = alloc_preg (cfg);
1693                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1694                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1695                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1696                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1697                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1698                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1699                 } else if (klass->cast_class == mono_defaults.enum_class) {
1700                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1701                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1702                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1703                 } else {
1704                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1705                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1706                 }
1707
1708                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1709                         /* Check that the object is a vector too */
1710                         int bounds_reg = alloc_preg (cfg);
1711                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1712                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1713                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1714                 }
1715         } else {
1716                 int idepth_reg = alloc_preg (cfg);
1717                 int stypes_reg = alloc_preg (cfg);
1718                 int stype = alloc_preg (cfg);
1719
1720                 mono_class_setup_supertypes (klass);
1721
1722                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1723                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1724                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1725                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1726                 }
1727                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1728                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1729                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1730         }
1731 }
1732
1733 static void
1734 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1735 {
1736         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1737 }
1738
1739 static void 
1740 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1741 {
1742         int val_reg;
1743
1744         g_assert (val == 0);
1745
1746         if (align == 0)
1747                 align = 4;
1748
1749         if ((size <= 4) && (size <= align)) {
1750                 switch (size) {
1751                 case 1:
1752                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1753                         return;
1754                 case 2:
1755                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1756                         return;
1757                 case 4:
1758                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1759                         return;
1760 #if SIZEOF_REGISTER == 8
1761                 case 8:
1762                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1763                         return;
1764 #endif
1765                 }
1766         }
1767
1768         val_reg = alloc_preg (cfg);
1769
1770         if (SIZEOF_REGISTER == 8)
1771                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1772         else
1773                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1774
1775         if (align < 4) {
1776                 /* This could be optimized further if neccesary */
1777                 while (size >= 1) {
1778                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1779                         offset += 1;
1780                         size -= 1;
1781                 }
1782                 return;
1783         }       
1784
1785 #if !NO_UNALIGNED_ACCESS
1786         if (SIZEOF_REGISTER == 8) {
1787                 if (offset % 8) {
1788                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1789                         offset += 4;
1790                         size -= 4;
1791                 }
1792                 while (size >= 8) {
1793                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1794                         offset += 8;
1795                         size -= 8;
1796                 }
1797         }       
1798 #endif
1799
1800         while (size >= 4) {
1801                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1802                 offset += 4;
1803                 size -= 4;
1804         }
1805         while (size >= 2) {
1806                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1807                 offset += 2;
1808                 size -= 2;
1809         }
1810         while (size >= 1) {
1811                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1812                 offset += 1;
1813                 size -= 1;
1814         }
1815 }
1816
1817 void 
1818 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1819 {
1820         int cur_reg;
1821
1822         if (align == 0)
1823                 align = 4;
1824
1825         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1826         g_assert (size < 10000);
1827
1828         if (align < 4) {
1829                 /* This could be optimized further if neccesary */
1830                 while (size >= 1) {
1831                         cur_reg = alloc_preg (cfg);
1832                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1833                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1834                         doffset += 1;
1835                         soffset += 1;
1836                         size -= 1;
1837                 }
1838         }
1839
1840 #if !NO_UNALIGNED_ACCESS
1841         if (SIZEOF_REGISTER == 8) {
1842                 while (size >= 8) {
1843                         cur_reg = alloc_preg (cfg);
1844                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1845                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1846                         doffset += 8;
1847                         soffset += 8;
1848                         size -= 8;
1849                 }
1850         }       
1851 #endif
1852
1853         while (size >= 4) {
1854                 cur_reg = alloc_preg (cfg);
1855                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1857                 doffset += 4;
1858                 soffset += 4;
1859                 size -= 4;
1860         }
1861         while (size >= 2) {
1862                 cur_reg = alloc_preg (cfg);
1863                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1864                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1865                 doffset += 2;
1866                 soffset += 2;
1867                 size -= 2;
1868         }
1869         while (size >= 1) {
1870                 cur_reg = alloc_preg (cfg);
1871                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1872                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1873                 doffset += 1;
1874                 soffset += 1;
1875                 size -= 1;
1876         }
1877 }
1878
1879 static void
1880 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1881 {
1882         MonoInst *ins, *c;
1883
1884         if (cfg->compile_aot) {
1885                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1886                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1887                 ins->sreg1 = sreg1;
1888                 ins->sreg2 = c->dreg;
1889                 MONO_ADD_INS (cfg->cbb, ins);
1890         } else {
1891                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1892                 ins->sreg1 = sreg1;
1893                 ins->inst_offset = mini_get_tls_offset (tls_key);
1894                 MONO_ADD_INS (cfg->cbb, ins);
1895         }
1896 }
1897
1898 /*
1899  * emit_push_lmf:
1900  *
1901  *   Emit IR to push the current LMF onto the LMF stack.
1902  */
1903 static void
1904 emit_push_lmf (MonoCompile *cfg)
1905 {
1906         /*
1907          * Emit IR to push the LMF:
1908          * lmf_addr = <lmf_addr from tls>
1909          * lmf->lmf_addr = lmf_addr
1910          * lmf->prev_lmf = *lmf_addr
1911          * *lmf_addr = lmf
1912          */
1913         int lmf_reg, prev_lmf_reg;
1914         MonoInst *ins, *lmf_ins;
1915
1916         if (!cfg->lmf_ir)
1917                 return;
1918
1919         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1920                 /* Load current lmf */
1921                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1922                 g_assert (lmf_ins);
1923                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1924                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1925                 lmf_reg = ins->dreg;
1926                 /* Save previous_lmf */
1927                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1928                 /* Set new LMF */
1929                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1930         } else {
1931                 /*
1932                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1933                  */
1934                 if (!cfg->lmf_addr_var)
1935                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1936
1937                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1938                 if (lmf_ins) 
1939                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1940                 else
1941                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1942                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1943
1944                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1945                 lmf_reg = ins->dreg;
1946
1947                 prev_lmf_reg = alloc_preg (cfg);
1948                 /* Save previous_lmf */
1949                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1950                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1951                 /* Set new lmf */
1952                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1953         }
1954 }
1955
1956 /*
1957  * emit_pop_lmf:
1958  *
1959  *   Emit IR to pop the current LMF from the LMF stack.
1960  */
1961 static void
1962 emit_pop_lmf (MonoCompile *cfg)
1963 {
1964         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1965         MonoInst *ins;
1966
1967         if (!cfg->lmf_ir)
1968                 return;
1969
1970         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1971         lmf_reg = ins->dreg;
1972
1973         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1974                 /* Load previous_lmf */
1975                 prev_lmf_reg = alloc_preg (cfg);
1976                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1977                 /* Set new LMF */
1978                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1979         } else {
1980                 /*
1981                  * Emit IR to pop the LMF:
1982                  * *(lmf->lmf_addr) = lmf->prev_lmf
1983                  */
1984                 /* This could be called before emit_push_lmf () */
1985                 if (!cfg->lmf_addr_var)
1986                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1987                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1988
1989                 prev_lmf_reg = alloc_preg (cfg);
1990                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1991                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1992         }
1993 }
1994
1995 static int
1996 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1997 {
1998         if (type->byref)
1999                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2000
2001 handle_enum:
2002         type = mini_get_basic_type_from_generic (gsctx, type);
2003         type = mini_replace_type (type);
2004         switch (type->type) {
2005         case MONO_TYPE_VOID:
2006                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2007         case MONO_TYPE_I1:
2008         case MONO_TYPE_U1:
2009         case MONO_TYPE_BOOLEAN:
2010         case MONO_TYPE_I2:
2011         case MONO_TYPE_U2:
2012         case MONO_TYPE_CHAR:
2013         case MONO_TYPE_I4:
2014         case MONO_TYPE_U4:
2015                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2016         case MONO_TYPE_I:
2017         case MONO_TYPE_U:
2018         case MONO_TYPE_PTR:
2019         case MONO_TYPE_FNPTR:
2020                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2021         case MONO_TYPE_CLASS:
2022         case MONO_TYPE_STRING:
2023         case MONO_TYPE_OBJECT:
2024         case MONO_TYPE_SZARRAY:
2025         case MONO_TYPE_ARRAY:    
2026                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2027         case MONO_TYPE_I8:
2028         case MONO_TYPE_U8:
2029                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2030         case MONO_TYPE_R4:
2031         case MONO_TYPE_R8:
2032                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2033         case MONO_TYPE_VALUETYPE:
2034                 if (type->data.klass->enumtype) {
2035                         type = mono_class_enum_basetype (type->data.klass);
2036                         goto handle_enum;
2037                 } else
2038                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2039         case MONO_TYPE_TYPEDBYREF:
2040                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2041         case MONO_TYPE_GENERICINST:
2042                 type = &type->data.generic_class->container_class->byval_arg;
2043                 goto handle_enum;
2044         case MONO_TYPE_VAR:
2045         case MONO_TYPE_MVAR:
2046                 /* gsharedvt */
2047                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2048         default:
2049                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2050         }
2051         return -1;
2052 }
2053
2054 /*
2055  * target_type_is_incompatible:
2056  * @cfg: MonoCompile context
2057  *
2058  * Check that the item @arg on the evaluation stack can be stored
2059  * in the target type (can be a local, or field, etc).
2060  * The cfg arg can be used to check if we need verification or just
2061  * validity checks.
2062  *
2063  * Returns: non-0 value if arg can't be stored on a target.
2064  */
2065 static int
2066 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2067 {
2068         MonoType *simple_type;
2069         MonoClass *klass;
2070
2071         target = mini_replace_type (target);
2072         if (target->byref) {
2073                 /* FIXME: check that the pointed to types match */
2074                 if (arg->type == STACK_MP)
2075                         return arg->klass != mono_class_from_mono_type (target);
2076                 if (arg->type == STACK_PTR)
2077                         return 0;
2078                 return 1;
2079         }
2080
2081         simple_type = mono_type_get_underlying_type (target);
2082         switch (simple_type->type) {
2083         case MONO_TYPE_VOID:
2084                 return 1;
2085         case MONO_TYPE_I1:
2086         case MONO_TYPE_U1:
2087         case MONO_TYPE_BOOLEAN:
2088         case MONO_TYPE_I2:
2089         case MONO_TYPE_U2:
2090         case MONO_TYPE_CHAR:
2091         case MONO_TYPE_I4:
2092         case MONO_TYPE_U4:
2093                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2094                         return 1;
2095                 return 0;
2096         case MONO_TYPE_PTR:
2097                 /* STACK_MP is needed when setting pinned locals */
2098                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2099                         return 1;
2100                 return 0;
2101         case MONO_TYPE_I:
2102         case MONO_TYPE_U:
2103         case MONO_TYPE_FNPTR:
2104                 /* 
2105                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2106                  * in native int. (#688008).
2107                  */
2108                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2109                         return 1;
2110                 return 0;
2111         case MONO_TYPE_CLASS:
2112         case MONO_TYPE_STRING:
2113         case MONO_TYPE_OBJECT:
2114         case MONO_TYPE_SZARRAY:
2115         case MONO_TYPE_ARRAY:    
2116                 if (arg->type != STACK_OBJ)
2117                         return 1;
2118                 /* FIXME: check type compatibility */
2119                 return 0;
2120         case MONO_TYPE_I8:
2121         case MONO_TYPE_U8:
2122                 if (arg->type != STACK_I8)
2123                         return 1;
2124                 return 0;
2125         case MONO_TYPE_R4:
2126         case MONO_TYPE_R8:
2127                 if (arg->type != STACK_R8)
2128                         return 1;
2129                 return 0;
2130         case MONO_TYPE_VALUETYPE:
2131                 if (arg->type != STACK_VTYPE)
2132                         return 1;
2133                 klass = mono_class_from_mono_type (simple_type);
2134                 if (klass != arg->klass)
2135                         return 1;
2136                 return 0;
2137         case MONO_TYPE_TYPEDBYREF:
2138                 if (arg->type != STACK_VTYPE)
2139                         return 1;
2140                 klass = mono_class_from_mono_type (simple_type);
2141                 if (klass != arg->klass)
2142                         return 1;
2143                 return 0;
2144         case MONO_TYPE_GENERICINST:
2145                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2146                         if (arg->type != STACK_VTYPE)
2147                                 return 1;
2148                         klass = mono_class_from_mono_type (simple_type);
2149                         if (klass != arg->klass)
2150                                 return 1;
2151                         return 0;
2152                 } else {
2153                         if (arg->type != STACK_OBJ)
2154                                 return 1;
2155                         /* FIXME: check type compatibility */
2156                         return 0;
2157                 }
2158         case MONO_TYPE_VAR:
2159         case MONO_TYPE_MVAR:
2160                 g_assert (cfg->generic_sharing_context);
2161                 if (mini_type_var_is_vt (cfg, simple_type)) {
2162                         if (arg->type != STACK_VTYPE)
2163                                 return 1;
2164                 } else {
2165                         if (arg->type != STACK_OBJ)
2166                                 return 1;
2167                 }
2168                 return 0;
2169         default:
2170                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2171         }
2172         return 1;
2173 }
2174
2175 /*
2176  * Prepare arguments for passing to a function call.
2177  * Return a non-zero value if the arguments can't be passed to the given
2178  * signature.
2179  * The type checks are not yet complete and some conversions may need
2180  * casts on 32 or 64 bit architectures.
2181  *
2182  * FIXME: implement this using target_type_is_incompatible ()
2183  */
2184 static int
2185 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2186 {
2187         MonoType *simple_type;
2188         int i;
2189
2190         if (sig->hasthis) {
2191                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2192                         return 1;
2193                 args++;
2194         }
2195         for (i = 0; i < sig->param_count; ++i) {
2196                 if (sig->params [i]->byref) {
2197                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2198                                 return 1;
2199                         continue;
2200                 }
2201                 simple_type = sig->params [i];
2202                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2203 handle_enum:
2204                 switch (simple_type->type) {
2205                 case MONO_TYPE_VOID:
2206                         return 1;
2207                         continue;
2208                 case MONO_TYPE_I1:
2209                 case MONO_TYPE_U1:
2210                 case MONO_TYPE_BOOLEAN:
2211                 case MONO_TYPE_I2:
2212                 case MONO_TYPE_U2:
2213                 case MONO_TYPE_CHAR:
2214                 case MONO_TYPE_I4:
2215                 case MONO_TYPE_U4:
2216                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2217                                 return 1;
2218                         continue;
2219                 case MONO_TYPE_I:
2220                 case MONO_TYPE_U:
2221                 case MONO_TYPE_PTR:
2222                 case MONO_TYPE_FNPTR:
2223                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2224                                 return 1;
2225                         continue;
2226                 case MONO_TYPE_CLASS:
2227                 case MONO_TYPE_STRING:
2228                 case MONO_TYPE_OBJECT:
2229                 case MONO_TYPE_SZARRAY:
2230                 case MONO_TYPE_ARRAY:    
2231                         if (args [i]->type != STACK_OBJ)
2232                                 return 1;
2233                         continue;
2234                 case MONO_TYPE_I8:
2235                 case MONO_TYPE_U8:
2236                         if (args [i]->type != STACK_I8)
2237                                 return 1;
2238                         continue;
2239                 case MONO_TYPE_R4:
2240                 case MONO_TYPE_R8:
2241                         if (args [i]->type != STACK_R8)
2242                                 return 1;
2243                         continue;
2244                 case MONO_TYPE_VALUETYPE:
2245                         if (simple_type->data.klass->enumtype) {
2246                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2247                                 goto handle_enum;
2248                         }
2249                         if (args [i]->type != STACK_VTYPE)
2250                                 return 1;
2251                         continue;
2252                 case MONO_TYPE_TYPEDBYREF:
2253                         if (args [i]->type != STACK_VTYPE)
2254                                 return 1;
2255                         continue;
2256                 case MONO_TYPE_GENERICINST:
2257                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2258                         goto handle_enum;
2259                 case MONO_TYPE_VAR:
2260                 case MONO_TYPE_MVAR:
2261                         /* gsharedvt */
2262                         if (args [i]->type != STACK_VTYPE)
2263                                 return 1;
2264                         continue;
2265                 default:
2266                         g_error ("unknown type 0x%02x in check_call_signature",
2267                                  simple_type->type);
2268                 }
2269         }
2270         return 0;
2271 }
2272
2273 static int
2274 callvirt_to_call (int opcode)
2275 {
2276         switch (opcode) {
2277         case OP_CALL_MEMBASE:
2278                 return OP_CALL;
2279         case OP_VOIDCALL_MEMBASE:
2280                 return OP_VOIDCALL;
2281         case OP_FCALL_MEMBASE:
2282                 return OP_FCALL;
2283         case OP_VCALL_MEMBASE:
2284                 return OP_VCALL;
2285         case OP_LCALL_MEMBASE:
2286                 return OP_LCALL;
2287         default:
2288                 g_assert_not_reached ();
2289         }
2290
2291         return -1;
2292 }
2293
2294 #ifdef MONO_ARCH_HAVE_IMT
2295 /* Either METHOD or IMT_ARG needs to be set */
2296 static void
2297 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2298 {
2299         int method_reg;
2300
2301         if (COMPILE_LLVM (cfg)) {
2302                 method_reg = alloc_preg (cfg);
2303
2304                 if (imt_arg) {
2305                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2306                 } else if (cfg->compile_aot) {
2307                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2308                 } else {
2309                         MonoInst *ins;
2310                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2311                         ins->inst_p0 = method;
2312                         ins->dreg = method_reg;
2313                         MONO_ADD_INS (cfg->cbb, ins);
2314                 }
2315
2316 #ifdef ENABLE_LLVM
2317                 call->imt_arg_reg = method_reg;
2318 #endif
2319 #ifdef MONO_ARCH_IMT_REG
2320         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2321 #else
2322         /* Need this to keep the IMT arg alive */
2323         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2324 #endif
2325                 return;
2326         }
2327
2328 #ifdef MONO_ARCH_IMT_REG
2329         method_reg = alloc_preg (cfg);
2330
2331         if (imt_arg) {
2332                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2333         } else if (cfg->compile_aot) {
2334                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2335         } else {
2336                 MonoInst *ins;
2337                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2338                 ins->inst_p0 = method;
2339                 ins->dreg = method_reg;
2340                 MONO_ADD_INS (cfg->cbb, ins);
2341         }
2342
2343         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2344 #else
2345         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2346 #endif
2347 }
2348 #endif
2349
2350 static MonoJumpInfo *
2351 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2352 {
2353         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2354
2355         ji->ip.i = ip;
2356         ji->type = type;
2357         ji->data.target = target;
2358
2359         return ji;
2360 }
2361
2362 static int
2363 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2364 {
2365         if (cfg->generic_sharing_context)
2366                 return mono_class_check_context_used (klass);
2367         else
2368                 return 0;
2369 }
2370
2371 static int
2372 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2373 {
2374         if (cfg->generic_sharing_context)
2375                 return mono_method_check_context_used (method);
2376         else
2377                 return 0;
2378 }
2379
2380 /*
2381  * check_method_sharing:
2382  *
2383  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2384  */
2385 static void
2386 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2387 {
2388         gboolean pass_vtable = FALSE;
2389         gboolean pass_mrgctx = FALSE;
2390
2391         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2392                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2393                 gboolean sharable = FALSE;
2394
2395                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2396                         sharable = TRUE;
2397                 } else {
2398                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2399                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2400                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2401
2402                         sharable = sharing_enabled && context_sharable;
2403                 }
2404
2405                 /*
2406                  * Pass vtable iff target method might
2407                  * be shared, which means that sharing
2408                  * is enabled for its class and its
2409                  * context is sharable (and it's not a
2410                  * generic method).
2411                  */
2412                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2413                         pass_vtable = TRUE;
2414         }
2415
2416         if (mini_method_get_context (cmethod) &&
2417                 mini_method_get_context (cmethod)->method_inst) {
2418                 g_assert (!pass_vtable);
2419
2420                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2421                         pass_mrgctx = TRUE;
2422                 } else {
2423                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2424                         MonoGenericContext *context = mini_method_get_context (cmethod);
2425                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2426
2427                         if (sharing_enabled && context_sharable)
2428                                 pass_mrgctx = TRUE;
2429                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2430                                 pass_mrgctx = TRUE;
2431                 }
2432         }
2433
2434         if (out_pass_vtable)
2435                 *out_pass_vtable = pass_vtable;
2436         if (out_pass_mrgctx)
2437                 *out_pass_mrgctx = pass_mrgctx;
2438 }
2439
2440 inline static MonoCallInst *
2441 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2442                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2443 {
2444         MonoType *sig_ret;
2445         MonoCallInst *call;
2446 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2447         int i;
2448 #endif
2449
2450         if (tail)
2451                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2452         else
2453                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2454
2455         call->args = args;
2456         call->signature = sig;
2457         call->rgctx_reg = rgctx;
2458         sig_ret = mini_replace_type (sig->ret);
2459
2460         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2461
2462         if (tail) {
2463                 if (mini_type_is_vtype (cfg, sig_ret)) {
2464                         call->vret_var = cfg->vret_addr;
2465                         //g_assert_not_reached ();
2466                 }
2467         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2468                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2469                 MonoInst *loada;
2470
2471                 temp->backend.is_pinvoke = sig->pinvoke;
2472
2473                 /*
2474                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2475                  * address of return value to increase optimization opportunities.
2476                  * Before vtype decomposition, the dreg of the call ins itself represents the
2477                  * fact the call modifies the return value. After decomposition, the call will
2478                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2479                  * will be transformed into an LDADDR.
2480                  */
2481                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2482                 loada->dreg = alloc_preg (cfg);
2483                 loada->inst_p0 = temp;
2484                 /* We reference the call too since call->dreg could change during optimization */
2485                 loada->inst_p1 = call;
2486                 MONO_ADD_INS (cfg->cbb, loada);
2487
2488                 call->inst.dreg = temp->dreg;
2489
2490                 call->vret_var = loada;
2491         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2492                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2493
2494 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2495         if (COMPILE_SOFT_FLOAT (cfg)) {
2496                 /* 
2497                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2498                  * an icall, but that cannot be done during the call sequence since it would clobber
2499                  * the call registers + the stack. So we do it before emitting the call.
2500                  */
2501                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2502                         MonoType *t;
2503                         MonoInst *in = call->args [i];
2504
2505                         if (i >= sig->hasthis)
2506                                 t = sig->params [i - sig->hasthis];
2507                         else
2508                                 t = &mono_defaults.int_class->byval_arg;
2509                         t = mono_type_get_underlying_type (t);
2510
2511                         if (!t->byref && t->type == MONO_TYPE_R4) {
2512                                 MonoInst *iargs [1];
2513                                 MonoInst *conv;
2514
2515                                 iargs [0] = in;
2516                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2517
2518                                 /* The result will be in an int vreg */
2519                                 call->args [i] = conv;
2520                         }
2521                 }
2522         }
2523 #endif
2524
2525         call->need_unbox_trampoline = unbox_trampoline;
2526
2527 #ifdef ENABLE_LLVM
2528         if (COMPILE_LLVM (cfg))
2529                 mono_llvm_emit_call (cfg, call);
2530         else
2531                 mono_arch_emit_call (cfg, call);
2532 #else
2533         mono_arch_emit_call (cfg, call);
2534 #endif
2535
2536         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2537         cfg->flags |= MONO_CFG_HAS_CALLS;
2538         
2539         return call;
2540 }
2541
2542 static void
2543 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2544 {
2545 #ifdef MONO_ARCH_RGCTX_REG
2546         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2547         cfg->uses_rgctx_reg = TRUE;
2548         call->rgctx_reg = TRUE;
2549 #ifdef ENABLE_LLVM
2550         call->rgctx_arg_reg = rgctx_reg;
2551 #endif
2552 #else
2553         NOT_IMPLEMENTED;
2554 #endif
2555 }       
2556
2557 inline static MonoInst*
2558 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2559 {
2560         MonoCallInst *call;
2561         int rgctx_reg = -1;
2562
2563         if (rgctx_arg) {
2564                 rgctx_reg = mono_alloc_preg (cfg);
2565                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2566         }
2567
2568         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2569
2570         call->inst.sreg1 = addr->dreg;
2571
2572         if (imt_arg)
2573                 emit_imt_argument (cfg, call, NULL, imt_arg);
2574
2575         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2576
2577         if (rgctx_arg)
2578                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2579
2580         return (MonoInst*)call;
2581 }
2582
2583 static MonoInst*
2584 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2585
2586 static MonoInst*
2587 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2588 static MonoInst*
2589 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2590
2591 static MonoInst*
2592 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2593                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2594 {
2595 #ifndef DISABLE_REMOTING
2596         gboolean might_be_remote = FALSE;
2597 #endif
2598         gboolean virtual = this != NULL;
2599         gboolean enable_for_aot = TRUE;
2600         int context_used;
2601         MonoCallInst *call;
2602         int rgctx_reg = 0;
2603         gboolean need_unbox_trampoline;
2604
2605         if (!sig)
2606                 sig = mono_method_signature (method);
2607
2608         if (rgctx_arg) {
2609                 rgctx_reg = mono_alloc_preg (cfg);
2610                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2611         }
2612
2613         if (method->string_ctor) {
2614                 /* Create the real signature */
2615                 /* FIXME: Cache these */
2616                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2617                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2618
2619                 sig = ctor_sig;
2620         }
2621
2622         context_used = mini_method_check_context_used (cfg, method);
2623
2624 #ifndef DISABLE_REMOTING
2625         might_be_remote = this && sig->hasthis &&
2626                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2627                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2628
2629         if (might_be_remote && context_used) {
2630                 MonoInst *addr;
2631
2632                 g_assert (cfg->generic_sharing_context);
2633
2634                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2635
2636                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2637         }
2638 #endif
2639
2640         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2641
2642         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2643
2644 #ifndef DISABLE_REMOTING
2645         if (might_be_remote)
2646                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2647         else
2648 #endif
2649                 call->method = method;
2650         call->inst.flags |= MONO_INST_HAS_METHOD;
2651         call->inst.inst_left = this;
2652         call->tail_call = tail;
2653
2654         if (virtual) {
2655                 int vtable_reg, slot_reg, this_reg;
2656                 int offset;
2657
2658                 this_reg = this->dreg;
2659
2660                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2661                         MonoInst *dummy_use;
2662
2663                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2664
2665                         /* Make a call to delegate->invoke_impl */
2666                         call->inst.inst_basereg = this_reg;
2667                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2668                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2669
2670                         /* We must emit a dummy use here because the delegate trampoline will
2671                         replace the 'this' argument with the delegate target making this activation
2672                         no longer a root for the delegate.
2673                         This is an issue for delegates that target collectible code such as dynamic
2674                         methods of GC'able assemblies.
2675
2676                         For a test case look into #667921.
2677
2678                         FIXME: a dummy use is not the best way to do it as the local register allocator
2679                         will put it on a caller save register and spil it around the call. 
2680                         Ideally, we would either put it on a callee save register or only do the store part.  
2681                          */
2682                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2683
2684                         return (MonoInst*)call;
2685                 }
2686
2687                 if ((!cfg->compile_aot || enable_for_aot) && 
2688                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2689                          (MONO_METHOD_IS_FINAL (method) &&
2690                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2691                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2692                         /* 
2693                          * the method is not virtual, we just need to ensure this is not null
2694                          * and then we can call the method directly.
2695                          */
2696 #ifndef DISABLE_REMOTING
2697                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2698                                 /* 
2699                                  * The check above ensures method is not gshared, this is needed since
2700                                  * gshared methods can't have wrappers.
2701                                  */
2702                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2703                         }
2704 #endif
2705
2706                         if (!method->string_ctor)
2707                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2708
2709                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2710                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2711                         /*
2712                          * the method is virtual, but we can statically dispatch since either
2713                          * it's class or the method itself are sealed.
2714                          * But first we need to ensure it's not a null reference.
2715                          */
2716                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2717
2718                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2719                 } else {
2720                         vtable_reg = alloc_preg (cfg);
2721                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2722                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2723                                 slot_reg = -1;
2724 #ifdef MONO_ARCH_HAVE_IMT
2725                                 if (mono_use_imt) {
2726                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2727                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2728                                         slot_reg = vtable_reg;
2729                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2730                                 }
2731 #endif
2732                                 if (slot_reg == -1) {
2733                                         slot_reg = alloc_preg (cfg);
2734                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2735                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2736                                 }
2737                         } else {
2738                                 slot_reg = vtable_reg;
2739                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2740                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2741 #ifdef MONO_ARCH_HAVE_IMT
2742                                 if (imt_arg) {
2743                                         g_assert (mono_method_signature (method)->generic_param_count);
2744                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2745                                 }
2746 #endif
2747                         }
2748
2749                         call->inst.sreg1 = slot_reg;
2750                         call->inst.inst_offset = offset;
2751                         call->virtual = TRUE;
2752                 }
2753         }
2754
2755         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2756
2757         if (rgctx_arg)
2758                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2759
2760         return (MonoInst*)call;
2761 }
2762
2763 MonoInst*
2764 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2765 {
2766         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2767 }
2768
2769 MonoInst*
2770 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2771                                            MonoInst **args)
2772 {
2773         MonoCallInst *call;
2774
2775         g_assert (sig);
2776
2777         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2778         call->fptr = func;
2779
2780         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2781
2782         return (MonoInst*)call;
2783 }
2784
2785 MonoInst*
2786 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2787 {
2788         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2789
2790         g_assert (info);
2791
2792         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2793 }
2794
2795 /*
2796  * mono_emit_abs_call:
2797  *
2798  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2799  */
2800 inline static MonoInst*
2801 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2802                                         MonoMethodSignature *sig, MonoInst **args)
2803 {
2804         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2805         MonoInst *ins;
2806
2807         /* 
2808          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2809          * handle it.
2810          */
2811         if (cfg->abs_patches == NULL)
2812                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2813         g_hash_table_insert (cfg->abs_patches, ji, ji);
2814         ins = mono_emit_native_call (cfg, ji, sig, args);
2815         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2816         return ins;
2817 }
2818  
2819 static MonoInst*
2820 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2821 {
2822         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2823                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2824                         int widen_op = -1;
2825
2826                         /* 
2827                          * Native code might return non register sized integers 
2828                          * without initializing the upper bits.
2829                          */
2830                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2831                         case OP_LOADI1_MEMBASE:
2832                                 widen_op = OP_ICONV_TO_I1;
2833                                 break;
2834                         case OP_LOADU1_MEMBASE:
2835                                 widen_op = OP_ICONV_TO_U1;
2836                                 break;
2837                         case OP_LOADI2_MEMBASE:
2838                                 widen_op = OP_ICONV_TO_I2;
2839                                 break;
2840                         case OP_LOADU2_MEMBASE:
2841                                 widen_op = OP_ICONV_TO_U2;
2842                                 break;
2843                         default:
2844                                 break;
2845                         }
2846
2847                         if (widen_op != -1) {
2848                                 int dreg = alloc_preg (cfg);
2849                                 MonoInst *widen;
2850
2851                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2852                                 widen->type = ins->type;
2853                                 ins = widen;
2854                         }
2855                 }
2856         }
2857
2858         return ins;
2859 }
2860
2861 static MonoMethod*
2862 get_memcpy_method (void)
2863 {
2864         static MonoMethod *memcpy_method = NULL;
2865         if (!memcpy_method) {
2866                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2867                 if (!memcpy_method)
2868                         g_error ("Old corlib found. Install a new one");
2869         }
2870         return memcpy_method;
2871 }
2872
2873 static void
2874 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2875 {
2876         MonoClassField *field;
2877         gpointer iter = NULL;
2878
2879         while ((field = mono_class_get_fields (klass, &iter))) {
2880                 int foffset;
2881
2882                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2883                         continue;
2884                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2885                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2886                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2887                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2888                 } else {
2889                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2890                         if (field_class->has_references)
2891                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2892                 }
2893         }
2894 }
2895
2896 static void
2897 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2898 {
2899         int card_table_shift_bits;
2900         gpointer card_table_mask;
2901         guint8 *card_table;
2902         MonoInst *dummy_use;
2903         int nursery_shift_bits;
2904         size_t nursery_size;
2905         gboolean has_card_table_wb = FALSE;
2906
2907         if (!cfg->gen_write_barriers)
2908                 return;
2909
2910         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2911
2912         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2913
2914 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER_IN_AOT
2915         if (cfg->compile_aot)
2916                 has_card_table_wb = TRUE;
2917 #endif
2918 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2919         if (!cfg->compile_aot)
2920                 has_card_table_wb = TRUE;
2921 #endif
2922
2923         if (has_card_table_wb && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2924                 MonoInst *wbarrier;
2925
2926                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2927                 wbarrier->sreg1 = ptr->dreg;
2928                 wbarrier->sreg2 = value->dreg;
2929                 MONO_ADD_INS (cfg->cbb, wbarrier);
2930         } else if (card_table) {
2931                 int offset_reg = alloc_preg (cfg);
2932                 int card_reg  = alloc_preg (cfg);
2933                 MonoInst *ins;
2934
2935                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2936                 if (card_table_mask)
2937                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2938
2939                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2940                  * IMM's larger than 32bits.
2941                  */
2942                 if (cfg->compile_aot) {
2943                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2944                 } else {
2945                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2946                         ins->inst_p0 = card_table;
2947                         ins->dreg = card_reg;
2948                         MONO_ADD_INS (cfg->cbb, ins);
2949                 }
2950
2951                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2952                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2953         } else {
2954                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2955                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2956         }
2957
2958         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2959 }
2960
2961 static gboolean
2962 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2963 {
2964         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2965         unsigned need_wb = 0;
2966
2967         if (align == 0)
2968                 align = 4;
2969
2970         /*types with references can't have alignment smaller than sizeof(void*) */
2971         if (align < SIZEOF_VOID_P)
2972                 return FALSE;
2973
2974         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2975         if (size > 32 * SIZEOF_VOID_P)
2976                 return FALSE;
2977
2978         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
2979
2980         /* We don't unroll more than 5 stores to avoid code bloat. */
2981         if (size > 5 * SIZEOF_VOID_P) {
2982                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2983                 size += (SIZEOF_VOID_P - 1);
2984                 size &= ~(SIZEOF_VOID_P - 1);
2985
2986                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2987                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2988                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2989                 return TRUE;
2990         }
2991
2992         destreg = iargs [0]->dreg;
2993         srcreg = iargs [1]->dreg;
2994         offset = 0;
2995
2996         dest_ptr_reg = alloc_preg (cfg);
2997         tmp_reg = alloc_preg (cfg);
2998
2999         /*tmp = dreg*/
3000         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3001
3002         while (size >= SIZEOF_VOID_P) {
3003                 MonoInst *load_inst;
3004                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3005                 load_inst->dreg = tmp_reg;
3006                 load_inst->inst_basereg = srcreg;
3007                 load_inst->inst_offset = offset;
3008                 MONO_ADD_INS (cfg->cbb, load_inst);
3009
3010                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3011
3012                 if (need_wb & 0x1)
3013                         emit_write_barrier (cfg, iargs [0], load_inst);
3014
3015                 offset += SIZEOF_VOID_P;
3016                 size -= SIZEOF_VOID_P;
3017                 need_wb >>= 1;
3018
3019                 /*tmp += sizeof (void*)*/
3020                 if (size >= SIZEOF_VOID_P) {
3021                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3022                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3023                 }
3024         }
3025
3026         /* Those cannot be references since size < sizeof (void*) */
3027         while (size >= 4) {
3028                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3029                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3030                 offset += 4;
3031                 size -= 4;
3032         }
3033
3034         while (size >= 2) {
3035                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3036                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3037                 offset += 2;
3038                 size -= 2;
3039         }
3040
3041         while (size >= 1) {
3042                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3043                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3044                 offset += 1;
3045                 size -= 1;
3046         }
3047
3048         return TRUE;
3049 }
3050
3051 /*
3052  * Emit code to copy a valuetype of type @klass whose address is stored in
3053  * @src->dreg to memory whose address is stored at @dest->dreg.
3054  */
3055 void
3056 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3057 {
3058         MonoInst *iargs [4];
3059         int context_used, n;
3060         guint32 align = 0;
3061         MonoMethod *memcpy_method;
3062         MonoInst *size_ins = NULL;
3063         MonoInst *memcpy_ins = NULL;
3064
3065         g_assert (klass);
3066         /*
3067          * This check breaks with spilled vars... need to handle it during verification anyway.
3068          * g_assert (klass && klass == src->klass && klass == dest->klass);
3069          */
3070
3071         if (mini_is_gsharedvt_klass (cfg, klass)) {
3072                 g_assert (!native);
3073                 context_used = mini_class_check_context_used (cfg, klass);
3074                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3075                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3076         }
3077
3078         if (native)
3079                 n = mono_class_native_size (klass, &align);
3080         else
3081                 n = mono_class_value_size (klass, &align);
3082
3083         /* if native is true there should be no references in the struct */
3084         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3085                 /* Avoid barriers when storing to the stack */
3086                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3087                           (dest->opcode == OP_LDADDR))) {
3088                         int context_used;
3089
3090                         iargs [0] = dest;
3091                         iargs [1] = src;
3092
3093                         context_used = mini_class_check_context_used (cfg, klass);
3094
3095                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3096                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3097                                 return;
3098                         } else if (context_used) {
3099                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3100                         }  else {
3101                                 if (cfg->compile_aot) {
3102                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3103                                 } else {
3104                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3105                                         mono_class_compute_gc_descriptor (klass);
3106                                 }
3107                         }
3108
3109                         if (size_ins)
3110                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3111                         else
3112                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3113                         return;
3114                 }
3115         }
3116
3117         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3118                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3119                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3120         } else {
3121                 iargs [0] = dest;
3122                 iargs [1] = src;
3123                 if (size_ins)
3124                         iargs [2] = size_ins;
3125                 else
3126                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3127                 
3128                 memcpy_method = get_memcpy_method ();
3129                 if (memcpy_ins)
3130                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3131                 else
3132                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3133         }
3134 }
3135
3136 static MonoMethod*
3137 get_memset_method (void)
3138 {
3139         static MonoMethod *memset_method = NULL;
3140         if (!memset_method) {
3141                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3142                 if (!memset_method)
3143                         g_error ("Old corlib found. Install a new one");
3144         }
3145         return memset_method;
3146 }
3147
3148 void
3149 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3150 {
3151         MonoInst *iargs [3];
3152         int n, context_used;
3153         guint32 align;
3154         MonoMethod *memset_method;
3155         MonoInst *size_ins = NULL;
3156         MonoInst *bzero_ins = NULL;
3157         static MonoMethod *bzero_method;
3158
3159         /* FIXME: Optimize this for the case when dest is an LDADDR */
3160
3161         mono_class_init (klass);
3162         if (mini_is_gsharedvt_klass (cfg, klass)) {
3163                 context_used = mini_class_check_context_used (cfg, klass);
3164                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3165                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3166                 if (!bzero_method)
3167                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3168                 g_assert (bzero_method);
3169                 iargs [0] = dest;
3170                 iargs [1] = size_ins;
3171                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3172                 return;
3173         }
3174
3175         n = mono_class_value_size (klass, &align);
3176
3177         if (n <= sizeof (gpointer) * 5) {
3178                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3179         }
3180         else {
3181                 memset_method = get_memset_method ();
3182                 iargs [0] = dest;
3183                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3184                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3185                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3186         }
3187 }
3188
3189 static MonoInst*
3190 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3191 {
3192         MonoInst *this = NULL;
3193
3194         g_assert (cfg->generic_sharing_context);
3195
3196         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3197                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3198                         !method->klass->valuetype)
3199                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3200
3201         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3202                 MonoInst *mrgctx_loc, *mrgctx_var;
3203
3204                 g_assert (!this);
3205                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3206
3207                 mrgctx_loc = mono_get_vtable_var (cfg);
3208                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3209
3210                 return mrgctx_var;
3211         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3212                 MonoInst *vtable_loc, *vtable_var;
3213
3214                 g_assert (!this);
3215
3216                 vtable_loc = mono_get_vtable_var (cfg);
3217                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3218
3219                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3220                         MonoInst *mrgctx_var = vtable_var;
3221                         int vtable_reg;
3222
3223                         vtable_reg = alloc_preg (cfg);
3224                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3225                         vtable_var->type = STACK_PTR;
3226                 }
3227
3228                 return vtable_var;
3229         } else {
3230                 MonoInst *ins;
3231                 int vtable_reg;
3232         
3233                 vtable_reg = alloc_preg (cfg);
3234                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3235                 return ins;
3236         }
3237 }
3238
3239 static MonoJumpInfoRgctxEntry *
3240 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3241 {
3242         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3243         res->method = method;
3244         res->in_mrgctx = in_mrgctx;
3245         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3246         res->data->type = patch_type;
3247         res->data->data.target = patch_data;
3248         res->info_type = info_type;
3249
3250         return res;
3251 }
3252
3253 static inline MonoInst*
3254 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3255 {
3256         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3257 }
3258
3259 static MonoInst*
3260 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3261                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3262 {
3263         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);
3264         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3265
3266         return emit_rgctx_fetch (cfg, rgctx, entry);
3267 }
3268
3269 static MonoInst*
3270 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3271                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3272 {
3273         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);
3274         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3275
3276         return emit_rgctx_fetch (cfg, rgctx, entry);
3277 }
3278
3279 static MonoInst*
3280 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3281                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3282 {
3283         MonoJumpInfoGSharedVtCall *call_info;
3284         MonoJumpInfoRgctxEntry *entry;
3285         MonoInst *rgctx;
3286
3287         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3288         call_info->sig = sig;
3289         call_info->method = cmethod;
3290
3291         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);
3292         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3293
3294         return emit_rgctx_fetch (cfg, rgctx, entry);
3295 }
3296
3297
3298 static MonoInst*
3299 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3300                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3301 {
3302         MonoJumpInfoRgctxEntry *entry;
3303         MonoInst *rgctx;
3304
3305         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);
3306         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3307
3308         return emit_rgctx_fetch (cfg, rgctx, entry);
3309 }
3310
3311 /*
3312  * emit_get_rgctx_method:
3313  *
3314  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3315  * normal constants, else emit a load from the rgctx.
3316  */
3317 static MonoInst*
3318 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3319                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3320 {
3321         if (!context_used) {
3322                 MonoInst *ins;
3323
3324                 switch (rgctx_type) {
3325                 case MONO_RGCTX_INFO_METHOD:
3326                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3327                         return ins;
3328                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3329                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3330                         return ins;
3331                 default:
3332                         g_assert_not_reached ();
3333                 }
3334         } else {
3335                 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);
3336                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3337
3338                 return emit_rgctx_fetch (cfg, rgctx, entry);
3339         }
3340 }
3341
3342 static MonoInst*
3343 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3344                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3345 {
3346         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);
3347         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3348
3349         return emit_rgctx_fetch (cfg, rgctx, entry);
3350 }
3351
3352 static int
3353 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3354 {
3355         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3356         MonoRuntimeGenericContextInfoTemplate *template;
3357         int i, idx;
3358
3359         g_assert (info);
3360
3361         for (i = 0; i < info->num_entries; ++i) {
3362                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3363
3364                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3365                         return i;
3366         }
3367
3368         if (info->num_entries == info->count_entries) {
3369                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3370                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3371
3372                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3373
3374                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3375                 info->entries = new_entries;
3376                 info->count_entries = new_count_entries;
3377         }
3378
3379         idx = info->num_entries;
3380         template = &info->entries [idx];
3381         template->info_type = rgctx_type;
3382         template->data = data;
3383
3384         info->num_entries ++;
3385
3386         return idx;
3387 }
3388
3389 /*
3390  * emit_get_gsharedvt_info:
3391  *
3392  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3393  */
3394 static MonoInst*
3395 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3396 {
3397         MonoInst *ins;
3398         int idx, dreg;
3399
3400         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3401         /* Load info->entries [idx] */
3402         dreg = alloc_preg (cfg);
3403         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3404
3405         return ins;
3406 }
3407
3408 static MonoInst*
3409 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3410 {
3411         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3412 }
3413
3414 /*
3415  * On return the caller must check @klass for load errors.
3416  */
3417 static void
3418 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3419 {
3420         MonoInst *vtable_arg;
3421         MonoCallInst *call;
3422         int context_used;
3423
3424         context_used = mini_class_check_context_used (cfg, klass);
3425
3426         if (context_used) {
3427                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3428                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3429         } else {
3430                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3431
3432                 if (!vtable)
3433                         return;
3434                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3435         }
3436
3437         if (COMPILE_LLVM (cfg))
3438                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3439         else
3440                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3441 #ifdef MONO_ARCH_VTABLE_REG
3442         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3443         cfg->uses_vtable_reg = TRUE;
3444 #else
3445         NOT_IMPLEMENTED;
3446 #endif
3447 }
3448
3449 static void
3450 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3451 {
3452         MonoInst *ins;
3453
3454         if (cfg->gen_seq_points && cfg->method == method) {
3455                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3456                 if (nonempty_stack)
3457                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3458                 MONO_ADD_INS (cfg->cbb, ins);
3459         }
3460 }
3461
3462 static void
3463 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3464 {
3465         if (mini_get_debug_options ()->better_cast_details) {
3466                 int to_klass_reg = alloc_preg (cfg);
3467                 int vtable_reg = alloc_preg (cfg);
3468                 int klass_reg = alloc_preg (cfg);
3469                 MonoBasicBlock *is_null_bb = NULL;
3470                 MonoInst *tls_get;
3471
3472                 if (null_check) {
3473                         NEW_BBLOCK (cfg, is_null_bb);
3474
3475                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3476                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3477                 }
3478
3479                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3480                 if (!tls_get) {
3481                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3482                         exit (1);
3483                 }
3484
3485                 MONO_ADD_INS (cfg->cbb, tls_get);
3486                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3487                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3488
3489                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3490                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3491                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3492
3493                 if (null_check) {
3494                         MONO_START_BB (cfg, is_null_bb);
3495                         if (out_bblock)
3496                                 *out_bblock = cfg->cbb;
3497                 }
3498         }
3499 }
3500
3501 static void
3502 reset_cast_details (MonoCompile *cfg)
3503 {
3504         /* Reset the variables holding the cast details */
3505         if (mini_get_debug_options ()->better_cast_details) {
3506                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3507
3508                 MONO_ADD_INS (cfg->cbb, tls_get);
3509                 /* It is enough to reset the from field */
3510                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3511         }
3512 }
3513
3514 /*
3515  * On return the caller must check @array_class for load errors
3516  */
3517 static void
3518 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3519 {
3520         int vtable_reg = alloc_preg (cfg);
3521         int context_used;
3522
3523         context_used = mini_class_check_context_used (cfg, array_class);
3524
3525         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3526
3527         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3528
3529         if (cfg->opt & MONO_OPT_SHARED) {
3530                 int class_reg = alloc_preg (cfg);
3531                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3532                 if (cfg->compile_aot) {
3533                         int klass_reg = alloc_preg (cfg);
3534                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3535                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3536                 } else {
3537                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3538                 }
3539         } else if (context_used) {
3540                 MonoInst *vtable_ins;
3541
3542                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3543                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3544         } else {
3545                 if (cfg->compile_aot) {
3546                         int vt_reg;
3547                         MonoVTable *vtable;
3548
3549                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3550                                 return;
3551                         vt_reg = alloc_preg (cfg);
3552                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3553                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3554                 } else {
3555                         MonoVTable *vtable;
3556                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3557                                 return;
3558                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3559                 }
3560         }
3561         
3562         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3563
3564         reset_cast_details (cfg);
3565 }
3566
3567 /**
3568  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3569  * generic code is generated.
3570  */
3571 static MonoInst*
3572 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3573 {
3574         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3575
3576         if (context_used) {
3577                 MonoInst *rgctx, *addr;
3578
3579                 /* FIXME: What if the class is shared?  We might not
3580                    have to get the address of the method from the
3581                    RGCTX. */
3582                 addr = emit_get_rgctx_method (cfg, context_used, method,
3583                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3584
3585                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3586
3587                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3588         } else {
3589                 gboolean pass_vtable, pass_mrgctx;
3590                 MonoInst *rgctx_arg = NULL;
3591
3592                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3593                 g_assert (!pass_mrgctx);
3594
3595                 if (pass_vtable) {
3596                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3597
3598                         g_assert (vtable);
3599                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3600                 }
3601
3602                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3603         }
3604 }
3605
3606 static MonoInst*
3607 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3608 {
3609         MonoInst *add;
3610         int obj_reg;
3611         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3612         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3613         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3614         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3615
3616         obj_reg = sp [0]->dreg;
3617         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3618         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3619
3620         /* FIXME: generics */
3621         g_assert (klass->rank == 0);
3622                         
3623         // Check rank == 0
3624         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3625         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3626
3627         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3628         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3629
3630         if (context_used) {
3631                 MonoInst *element_class;
3632
3633                 /* This assertion is from the unboxcast insn */
3634                 g_assert (klass->rank == 0);
3635
3636                 element_class = emit_get_rgctx_klass (cfg, context_used,
3637                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3638
3639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3640                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3641         } else {
3642                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3643                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3644                 reset_cast_details (cfg);
3645         }
3646
3647         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3648         MONO_ADD_INS (cfg->cbb, add);
3649         add->type = STACK_MP;
3650         add->klass = klass;
3651
3652         return add;
3653 }
3654
3655 static MonoInst*
3656 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3657 {
3658         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3659         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3660         MonoInst *ins;
3661         int dreg, addr_reg;
3662
3663         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3664
3665         /* obj */
3666         args [0] = obj;
3667
3668         /* klass */
3669         args [1] = klass_inst;
3670
3671         /* CASTCLASS */
3672         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3673
3674         NEW_BBLOCK (cfg, is_ref_bb);
3675         NEW_BBLOCK (cfg, is_nullable_bb);
3676         NEW_BBLOCK (cfg, end_bb);
3677         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3678         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3679         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3680
3681         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3682         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3683
3684         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3685         addr_reg = alloc_dreg (cfg, STACK_MP);
3686
3687         /* Non-ref case */
3688         /* UNBOX */
3689         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3690         MONO_ADD_INS (cfg->cbb, addr);
3691
3692         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3693
3694         /* Ref case */
3695         MONO_START_BB (cfg, is_ref_bb);
3696
3697         /* Save the ref to a temporary */
3698         dreg = alloc_ireg (cfg);
3699         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3700         addr->dreg = addr_reg;
3701         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3702         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3703
3704         /* Nullable case */
3705         MONO_START_BB (cfg, is_nullable_bb);
3706
3707         {
3708                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3709                 MonoInst *unbox_call;
3710                 MonoMethodSignature *unbox_sig;
3711                 MonoInst *var;
3712
3713                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3714
3715                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3716                 unbox_sig->ret = &klass->byval_arg;
3717                 unbox_sig->param_count = 1;
3718                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3719                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3720
3721                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3722                 addr->dreg = addr_reg;
3723         }
3724
3725         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3726
3727         /* End */
3728         MONO_START_BB (cfg, end_bb);
3729
3730         /* LDOBJ */
3731         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3732
3733         *out_cbb = cfg->cbb;
3734
3735         return ins;
3736 }
3737
3738 /*
3739  * Returns NULL and set the cfg exception on error.
3740  */
3741 static MonoInst*
3742 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3743 {
3744         MonoInst *iargs [2];
3745         void *alloc_ftn;
3746
3747         if (context_used) {
3748                 MonoInst *data;
3749                 int rgctx_info;
3750                 MonoInst *iargs [2];
3751
3752                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3753
3754                 if (cfg->opt & MONO_OPT_SHARED)
3755                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3756                 else
3757                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3758                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3759
3760                 if (cfg->opt & MONO_OPT_SHARED) {
3761                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3762                         iargs [1] = data;
3763                         alloc_ftn = mono_object_new;
3764                 } else {
3765                         iargs [0] = data;
3766                         alloc_ftn = mono_object_new_specific;
3767                 }
3768
3769                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3770                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3771
3772                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3773         }
3774
3775         if (cfg->opt & MONO_OPT_SHARED) {
3776                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3777                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3778
3779                 alloc_ftn = mono_object_new;
3780         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3781                 /* This happens often in argument checking code, eg. throw new FooException... */
3782                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3783                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3784                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3785         } else {
3786                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3787                 MonoMethod *managed_alloc = NULL;
3788                 gboolean pass_lw;
3789
3790                 if (!vtable) {
3791                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3792                         cfg->exception_ptr = klass;
3793                         return NULL;
3794                 }
3795
3796 #ifndef MONO_CROSS_COMPILE
3797                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3798 #endif
3799
3800                 if (managed_alloc) {
3801                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3802                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3803                 }
3804                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3805                 if (pass_lw) {
3806                         guint32 lw = vtable->klass->instance_size;
3807                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3808                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3809                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3810                 }
3811                 else {
3812                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3813                 }
3814         }
3815
3816         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3817 }
3818         
3819 /*
3820  * Returns NULL and set the cfg exception on error.
3821  */     
3822 static MonoInst*
3823 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3824 {
3825         MonoInst *alloc, *ins;
3826
3827         *out_cbb = cfg->cbb;
3828
3829         if (mono_class_is_nullable (klass)) {
3830                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3831
3832                 if (context_used) {
3833                         /* FIXME: What if the class is shared?  We might not
3834                            have to get the method address from the RGCTX. */
3835                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3836                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3837                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3838
3839                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3840                 } else {
3841                         gboolean pass_vtable, pass_mrgctx;
3842                         MonoInst *rgctx_arg = NULL;
3843
3844                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3845                         g_assert (!pass_mrgctx);
3846
3847                         if (pass_vtable) {
3848                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3849
3850                                 g_assert (vtable);
3851                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3852                         }
3853
3854                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3855                 }
3856         }
3857
3858         if (mini_is_gsharedvt_klass (cfg, klass)) {
3859                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3860                 MonoInst *res, *is_ref, *src_var, *addr;
3861                 int addr_reg, dreg;
3862
3863                 dreg = alloc_ireg (cfg);
3864
3865                 NEW_BBLOCK (cfg, is_ref_bb);
3866                 NEW_BBLOCK (cfg, is_nullable_bb);
3867                 NEW_BBLOCK (cfg, end_bb);
3868                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3869                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3870                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3871
3872                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3873                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3874
3875                 /* Non-ref case */
3876                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3877                 if (!alloc)
3878                         return NULL;
3879                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3880                 ins->opcode = OP_STOREV_MEMBASE;
3881
3882                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3883                 res->type = STACK_OBJ;
3884                 res->klass = klass;
3885                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3886                 
3887                 /* Ref case */
3888                 MONO_START_BB (cfg, is_ref_bb);
3889                 addr_reg = alloc_ireg (cfg);
3890
3891                 /* val is a vtype, so has to load the value manually */
3892                 src_var = get_vreg_to_inst (cfg, val->dreg);
3893                 if (!src_var)
3894                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3895                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3896                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3897                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3898
3899                 /* Nullable case */
3900                 MONO_START_BB (cfg, is_nullable_bb);
3901
3902                 {
3903                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3904                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3905                         MonoInst *box_call;
3906                         MonoMethodSignature *box_sig;
3907
3908                         /*
3909                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3910                          * construct that method at JIT time, so have to do things by hand.
3911                          */
3912                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3913                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3914                         box_sig->param_count = 1;
3915                         box_sig->params [0] = &klass->byval_arg;
3916                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3917                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3918                         res->type = STACK_OBJ;
3919                         res->klass = klass;
3920                 }
3921
3922                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3923
3924                 MONO_START_BB (cfg, end_bb);
3925
3926                 *out_cbb = cfg->cbb;
3927
3928                 return res;
3929         } else {
3930                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3931                 if (!alloc)
3932                         return NULL;
3933
3934                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3935                 return alloc;
3936         }
3937 }
3938
3939
3940 static gboolean
3941 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3942 {
3943         int i;
3944         MonoGenericContainer *container;
3945         MonoGenericInst *ginst;
3946
3947         if (klass->generic_class) {
3948                 container = klass->generic_class->container_class->generic_container;
3949                 ginst = klass->generic_class->context.class_inst;
3950         } else if (klass->generic_container && context_used) {
3951                 container = klass->generic_container;
3952                 ginst = container->context.class_inst;
3953         } else {
3954                 return FALSE;
3955         }
3956
3957         for (i = 0; i < container->type_argc; ++i) {
3958                 MonoType *type;
3959                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
3960                         continue;
3961                 type = ginst->type_argv [i];
3962                 if (mini_type_is_reference (cfg, type))
3963                         return TRUE;
3964         }
3965         return FALSE;
3966 }
3967
3968 // FIXME: This doesn't work yet (class libs tests fail?)
3969 #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)
3970
3971 /*
3972  * Returns NULL and set the cfg exception on error.
3973  */
3974 static MonoInst*
3975 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3976 {
3977         MonoBasicBlock *is_null_bb;
3978         int obj_reg = src->dreg;
3979         int vtable_reg = alloc_preg (cfg);
3980         MonoInst *klass_inst = NULL;
3981
3982         if (context_used) {
3983                 MonoInst *args [3];
3984
3985                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
3986                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
3987                         MonoInst *cache_ins;
3988
3989                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3990
3991                         /* obj */
3992                         args [0] = src;
3993
3994                         /* klass - it's the second element of the cache entry*/
3995                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3996
3997                         /* cache */
3998                         args [2] = cache_ins;
3999
4000                         return mono_emit_method_call (cfg, mono_castclass, args, NULL);
4001                 }
4002
4003                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4004         }
4005
4006         NEW_BBLOCK (cfg, is_null_bb);
4007
4008         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4009         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4010
4011         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4012
4013         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4014                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4015                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4016         } else {
4017                 int klass_reg = alloc_preg (cfg);
4018
4019                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4020
4021                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4022                         /* the remoting code is broken, access the class for now */
4023                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4024                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4025                                 if (!vt) {
4026                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4027                                         cfg->exception_ptr = klass;
4028                                         return NULL;
4029                                 }
4030                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4031                         } else {
4032                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4033                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4034                         }
4035                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4036                 } else {
4037                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4038                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4039                 }
4040         }
4041
4042         MONO_START_BB (cfg, is_null_bb);
4043
4044         reset_cast_details (cfg);
4045
4046         return src;
4047 }
4048
4049 /*
4050  * Returns NULL and set the cfg exception on error.
4051  */
4052 static MonoInst*
4053 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4054 {
4055         MonoInst *ins;
4056         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4057         int obj_reg = src->dreg;
4058         int vtable_reg = alloc_preg (cfg);
4059         int res_reg = alloc_ireg_ref (cfg);
4060         MonoInst *klass_inst = NULL;
4061
4062         if (context_used) {
4063                 MonoInst *args [3];
4064
4065                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4066                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
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 mono_emit_method_call (cfg, mono_isinst, 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         NEW_BBLOCK (cfg, false_bb);
4088         NEW_BBLOCK (cfg, end_bb);
4089
4090         /* Do the assignment at the beginning, so the other assignment can be if converted */
4091         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4092         ins->type = STACK_OBJ;
4093         ins->klass = klass;
4094
4095         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4096         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4097
4098         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4099
4100         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4101                 g_assert (!context_used);
4102                 /* the is_null_bb target simply copies the input register to the output */
4103                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4104         } else {
4105                 int klass_reg = alloc_preg (cfg);
4106
4107                 if (klass->rank) {
4108                         int rank_reg = alloc_preg (cfg);
4109                         int eclass_reg = alloc_preg (cfg);
4110
4111                         g_assert (!context_used);
4112                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4113                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4114                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4115                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4116                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4117                         if (klass->cast_class == mono_defaults.object_class) {
4118                                 int parent_reg = alloc_preg (cfg);
4119                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4120                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4121                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4122                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4123                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4124                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4125                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4126                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4127                         } else if (klass->cast_class == mono_defaults.enum_class) {
4128                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4129                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4130                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4131                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4132                         } else {
4133                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4134                                         /* Check that the object is a vector too */
4135                                         int bounds_reg = alloc_preg (cfg);
4136                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4137                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4138                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4139                                 }
4140
4141                                 /* the is_null_bb target simply copies the input register to the output */
4142                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4143                         }
4144                 } else if (mono_class_is_nullable (klass)) {
4145                         g_assert (!context_used);
4146                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4147                         /* the is_null_bb target simply copies the input register to the output */
4148                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4149                 } else {
4150                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4151                                 g_assert (!context_used);
4152                                 /* the remoting code is broken, access the class for now */
4153                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4154                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4155                                         if (!vt) {
4156                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4157                                                 cfg->exception_ptr = klass;
4158                                                 return NULL;
4159                                         }
4160                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4161                                 } else {
4162                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4163                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4164                                 }
4165                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4166                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4167                         } else {
4168                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4169                                 /* the is_null_bb target simply copies the input register to the output */
4170                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4171                         }
4172                 }
4173         }
4174
4175         MONO_START_BB (cfg, false_bb);
4176
4177         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4178         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4179
4180         MONO_START_BB (cfg, is_null_bb);
4181
4182         MONO_START_BB (cfg, end_bb);
4183
4184         return ins;
4185 }
4186
4187 static MonoInst*
4188 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4189 {
4190         /* This opcode takes as input an object reference and a class, and returns:
4191         0) if the object is an instance of the class,
4192         1) if the object is not instance of the class,
4193         2) if the object is a proxy whose type cannot be determined */
4194
4195         MonoInst *ins;
4196 #ifndef DISABLE_REMOTING
4197         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4198 #else
4199         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4200 #endif
4201         int obj_reg = src->dreg;
4202         int dreg = alloc_ireg (cfg);
4203         int tmp_reg;
4204 #ifndef DISABLE_REMOTING
4205         int klass_reg = alloc_preg (cfg);
4206 #endif
4207
4208         NEW_BBLOCK (cfg, true_bb);
4209         NEW_BBLOCK (cfg, false_bb);
4210         NEW_BBLOCK (cfg, end_bb);
4211 #ifndef DISABLE_REMOTING
4212         NEW_BBLOCK (cfg, false2_bb);
4213         NEW_BBLOCK (cfg, no_proxy_bb);
4214 #endif
4215
4216         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4217         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4218
4219         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4220 #ifndef DISABLE_REMOTING
4221                 NEW_BBLOCK (cfg, interface_fail_bb);
4222 #endif
4223
4224                 tmp_reg = alloc_preg (cfg);
4225                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4226 #ifndef DISABLE_REMOTING
4227                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4228                 MONO_START_BB (cfg, interface_fail_bb);
4229                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4230                 
4231                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4232
4233                 tmp_reg = alloc_preg (cfg);
4234                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4235                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4236                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4237 #else
4238                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4239 #endif
4240         } else {
4241 #ifndef DISABLE_REMOTING
4242                 tmp_reg = alloc_preg (cfg);
4243                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4244                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4245
4246                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4247                 tmp_reg = alloc_preg (cfg);
4248                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4249                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4250
4251                 tmp_reg = alloc_preg (cfg);             
4252                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4253                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4254                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4255                 
4256                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4257                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4258
4259                 MONO_START_BB (cfg, no_proxy_bb);
4260
4261                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4262 #else
4263                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4264 #endif
4265         }
4266
4267         MONO_START_BB (cfg, false_bb);
4268
4269         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4270         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4271
4272 #ifndef DISABLE_REMOTING
4273         MONO_START_BB (cfg, false2_bb);
4274
4275         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4276         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4277 #endif
4278
4279         MONO_START_BB (cfg, true_bb);
4280
4281         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4282
4283         MONO_START_BB (cfg, end_bb);
4284
4285         /* FIXME: */
4286         MONO_INST_NEW (cfg, ins, OP_ICONST);
4287         ins->dreg = dreg;
4288         ins->type = STACK_I4;
4289
4290         return ins;
4291 }
4292
4293 static MonoInst*
4294 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4295 {
4296         /* This opcode takes as input an object reference and a class, and returns:
4297         0) if the object is an instance of the class,
4298         1) if the object is a proxy whose type cannot be determined
4299         an InvalidCastException exception is thrown otherwhise*/
4300         
4301         MonoInst *ins;
4302 #ifndef DISABLE_REMOTING
4303         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4304 #else
4305         MonoBasicBlock *ok_result_bb;
4306 #endif
4307         int obj_reg = src->dreg;
4308         int dreg = alloc_ireg (cfg);
4309         int tmp_reg = alloc_preg (cfg);
4310
4311 #ifndef DISABLE_REMOTING
4312         int klass_reg = alloc_preg (cfg);
4313         NEW_BBLOCK (cfg, end_bb);
4314 #endif
4315
4316         NEW_BBLOCK (cfg, ok_result_bb);
4317
4318         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4319         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4320
4321         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4322
4323         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4324 #ifndef DISABLE_REMOTING
4325                 NEW_BBLOCK (cfg, interface_fail_bb);
4326         
4327                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4328                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4329                 MONO_START_BB (cfg, interface_fail_bb);
4330                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4331
4332                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4333
4334                 tmp_reg = alloc_preg (cfg);             
4335                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4336                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4337                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4338                 
4339                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4340                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4341 #else
4342                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4343                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4344                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4345 #endif
4346         } else {
4347 #ifndef DISABLE_REMOTING
4348                 NEW_BBLOCK (cfg, no_proxy_bb);
4349
4350                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4351                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4352                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4353
4354                 tmp_reg = alloc_preg (cfg);
4355                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4356                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4357
4358                 tmp_reg = alloc_preg (cfg);
4359                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4360                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4361                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4362
4363                 NEW_BBLOCK (cfg, fail_1_bb);
4364                 
4365                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4366
4367                 MONO_START_BB (cfg, fail_1_bb);
4368
4369                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4370                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4371
4372                 MONO_START_BB (cfg, no_proxy_bb);
4373
4374                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4375 #else
4376                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4377 #endif
4378         }
4379
4380         MONO_START_BB (cfg, ok_result_bb);
4381
4382         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4383
4384 #ifndef DISABLE_REMOTING
4385         MONO_START_BB (cfg, end_bb);
4386 #endif
4387
4388         /* FIXME: */
4389         MONO_INST_NEW (cfg, ins, OP_ICONST);
4390         ins->dreg = dreg;
4391         ins->type = STACK_I4;
4392
4393         return ins;
4394 }
4395
4396 /*
4397  * Returns NULL and set the cfg exception on error.
4398  */
4399 static G_GNUC_UNUSED MonoInst*
4400 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4401 {
4402         MonoInst *ptr;
4403         int dreg;
4404         gpointer *trampoline;
4405         MonoInst *obj, *method_ins, *tramp_ins;
4406         MonoDomain *domain;
4407         guint8 **code_slot;
4408
4409         obj = handle_alloc (cfg, klass, FALSE, 0);
4410         if (!obj)
4411                 return NULL;
4412
4413         /* Inline the contents of mono_delegate_ctor */
4414
4415         /* Set target field */
4416         /* Optimize away setting of NULL target */
4417         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4418                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4419                 if (cfg->gen_write_barriers) {
4420                         dreg = alloc_preg (cfg);
4421                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4422                         emit_write_barrier (cfg, ptr, target);
4423                 }
4424         }
4425
4426         /* Set method field */
4427         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4428         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4429         if (cfg->gen_write_barriers) {
4430                 dreg = alloc_preg (cfg);
4431                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4432                 emit_write_barrier (cfg, ptr, method_ins);
4433         }
4434         /* 
4435          * To avoid looking up the compiled code belonging to the target method
4436          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4437          * store it, and we fill it after the method has been compiled.
4438          */
4439         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4440                 MonoInst *code_slot_ins;
4441
4442                 if (context_used) {
4443                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4444                 } else {
4445                         domain = mono_domain_get ();
4446                         mono_domain_lock (domain);
4447                         if (!domain_jit_info (domain)->method_code_hash)
4448                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4449                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4450                         if (!code_slot) {
4451                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4452                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4453                         }
4454                         mono_domain_unlock (domain);
4455
4456                         if (cfg->compile_aot)
4457                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4458                         else
4459                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4460                 }
4461                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4462         }
4463
4464         /* Set invoke_impl field */
4465         if (cfg->compile_aot) {
4466                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
4467         } else {
4468                 trampoline = mono_create_delegate_trampoline (cfg->domain, klass);
4469                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4470         }
4471         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4472
4473         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4474
4475         return obj;
4476 }
4477
4478 static MonoInst*
4479 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4480 {
4481         MonoJitICallInfo *info;
4482
4483         /* Need to register the icall so it gets an icall wrapper */
4484         info = mono_get_array_new_va_icall (rank);
4485
4486         cfg->flags |= MONO_CFG_HAS_VARARGS;
4487
4488         /* mono_array_new_va () needs a vararg calling convention */
4489         cfg->disable_llvm = TRUE;
4490
4491         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4492         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4493 }
4494
4495 static void
4496 mono_emit_load_got_addr (MonoCompile *cfg)
4497 {
4498         MonoInst *getaddr, *dummy_use;
4499
4500         if (!cfg->got_var || cfg->got_var_allocated)
4501                 return;
4502
4503         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4504         getaddr->cil_code = cfg->header->code;
4505         getaddr->dreg = cfg->got_var->dreg;
4506
4507         /* Add it to the start of the first bblock */
4508         if (cfg->bb_entry->code) {
4509                 getaddr->next = cfg->bb_entry->code;
4510                 cfg->bb_entry->code = getaddr;
4511         }
4512         else
4513                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4514
4515         cfg->got_var_allocated = TRUE;
4516
4517         /* 
4518          * Add a dummy use to keep the got_var alive, since real uses might
4519          * only be generated by the back ends.
4520          * Add it to end_bblock, so the variable's lifetime covers the whole
4521          * method.
4522          * It would be better to make the usage of the got var explicit in all
4523          * cases when the backend needs it (i.e. calls, throw etc.), so this
4524          * wouldn't be needed.
4525          */
4526         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4527         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4528 }
4529
4530 static int inline_limit;
4531 static gboolean inline_limit_inited;
4532
4533 static gboolean
4534 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4535 {
4536         MonoMethodHeaderSummary header;
4537         MonoVTable *vtable;
4538 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4539         MonoMethodSignature *sig = mono_method_signature (method);
4540         int i;
4541 #endif
4542
4543         if (cfg->generic_sharing_context)
4544                 return FALSE;
4545
4546         if (cfg->inline_depth > 10)
4547                 return FALSE;
4548
4549 #ifdef MONO_ARCH_HAVE_LMF_OPS
4550         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4551                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4552             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4553                 return TRUE;
4554 #endif
4555
4556
4557         if (!mono_method_get_header_summary (method, &header))
4558                 return FALSE;
4559
4560         /*runtime, icall and pinvoke are checked by summary call*/
4561         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4562             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4563             (mono_class_is_marshalbyref (method->klass)) ||
4564             header.has_clauses)
4565                 return FALSE;
4566
4567         /* also consider num_locals? */
4568         /* Do the size check early to avoid creating vtables */
4569         if (!inline_limit_inited) {
4570                 if (g_getenv ("MONO_INLINELIMIT"))
4571                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4572                 else
4573                         inline_limit = INLINE_LENGTH_LIMIT;
4574                 inline_limit_inited = TRUE;
4575         }
4576         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4577                 return FALSE;
4578
4579         /*
4580          * if we can initialize the class of the method right away, we do,
4581          * otherwise we don't allow inlining if the class needs initialization,
4582          * since it would mean inserting a call to mono_runtime_class_init()
4583          * inside the inlined code
4584          */
4585         if (!(cfg->opt & MONO_OPT_SHARED)) {
4586                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4587                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4588                         vtable = mono_class_vtable (cfg->domain, method->klass);
4589                         if (!vtable)
4590                                 return FALSE;
4591                         if (cfg->compile_aot && mono_class_needs_cctor_run (method->klass, NULL))
4592                                 return FALSE;
4593                         mono_runtime_class_init (vtable);
4594                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4595                         if (cfg->run_cctors && method->klass->has_cctor) {
4596                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4597                                 if (!method->klass->runtime_info)
4598                                         /* No vtable created yet */
4599                                         return FALSE;
4600                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4601                                 if (!vtable)
4602                                         return FALSE;
4603                                 /* This makes so that inline cannot trigger */
4604                                 /* .cctors: too many apps depend on them */
4605                                 /* running with a specific order... */
4606                                 if (! vtable->initialized)
4607                                         return FALSE;
4608                                 mono_runtime_class_init (vtable);
4609                         }
4610                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4611                         if (!method->klass->runtime_info)
4612                                 /* No vtable created yet */
4613                                 return FALSE;
4614                         vtable = mono_class_vtable (cfg->domain, method->klass);
4615                         if (!vtable)
4616                                 return FALSE;
4617                         if (!vtable->initialized)
4618                                 return FALSE;
4619                 }
4620         } else {
4621                 /* 
4622                  * If we're compiling for shared code
4623                  * the cctor will need to be run at aot method load time, for example,
4624                  * or at the end of the compilation of the inlining method.
4625                  */
4626                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4627                         return FALSE;
4628         }
4629
4630         /*
4631          * CAS - do not inline methods with declarative security
4632          * Note: this has to be before any possible return TRUE;
4633          */
4634         if (mono_security_method_has_declsec (method))
4635                 return FALSE;
4636
4637 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4638         if (mono_arch_is_soft_float ()) {
4639                 /* FIXME: */
4640                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4641                         return FALSE;
4642                 for (i = 0; i < sig->param_count; ++i)
4643                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4644                                 return FALSE;
4645         }
4646 #endif
4647
4648         return TRUE;
4649 }
4650
4651 static gboolean
4652 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4653 {
4654         if (!cfg->compile_aot) {
4655                 g_assert (vtable);
4656                 if (vtable->initialized)
4657                         return FALSE;
4658         }
4659
4660         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4661                 if (cfg->method == method)
4662                         return FALSE;
4663         }
4664
4665         if (!mono_class_needs_cctor_run (klass, method))
4666                 return FALSE;
4667
4668         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4669                 /* The initialization is already done before the method is called */
4670                 return FALSE;
4671
4672         return TRUE;
4673 }
4674
4675 static MonoInst*
4676 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4677 {
4678         MonoInst *ins;
4679         guint32 size;
4680         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4681         int context_used;
4682
4683         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4684                 size = -1;
4685         } else {
4686                 mono_class_init (klass);
4687                 size = mono_class_array_element_size (klass);
4688         }
4689
4690         mult_reg = alloc_preg (cfg);
4691         array_reg = arr->dreg;
4692         index_reg = index->dreg;
4693
4694 #if SIZEOF_REGISTER == 8
4695         /* The array reg is 64 bits but the index reg is only 32 */
4696         if (COMPILE_LLVM (cfg)) {
4697                 /* Not needed */
4698                 index2_reg = index_reg;
4699         } else {
4700                 index2_reg = alloc_preg (cfg);
4701                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4702         }
4703 #else
4704         if (index->type == STACK_I8) {
4705                 index2_reg = alloc_preg (cfg);
4706                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4707         } else {
4708                 index2_reg = index_reg;
4709         }
4710 #endif
4711
4712         if (bcheck)
4713                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4714
4715 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4716         if (size == 1 || size == 2 || size == 4 || size == 8) {
4717                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4718
4719                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4720                 ins->klass = mono_class_get_element_class (klass);
4721                 ins->type = STACK_MP;
4722
4723                 return ins;
4724         }
4725 #endif          
4726
4727         add_reg = alloc_ireg_mp (cfg);
4728
4729         if (size == -1) {
4730                 MonoInst *rgctx_ins;
4731
4732                 /* gsharedvt */
4733                 g_assert (cfg->generic_sharing_context);
4734                 context_used = mini_class_check_context_used (cfg, klass);
4735                 g_assert (context_used);
4736                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4737                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4738         } else {
4739                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4740         }
4741         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4742         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4743         ins->klass = mono_class_get_element_class (klass);
4744         ins->type = STACK_MP;
4745         MONO_ADD_INS (cfg->cbb, ins);
4746
4747         return ins;
4748 }
4749
4750 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4751 static MonoInst*
4752 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4753 {
4754         int bounds_reg = alloc_preg (cfg);
4755         int add_reg = alloc_ireg_mp (cfg);
4756         int mult_reg = alloc_preg (cfg);
4757         int mult2_reg = alloc_preg (cfg);
4758         int low1_reg = alloc_preg (cfg);
4759         int low2_reg = alloc_preg (cfg);
4760         int high1_reg = alloc_preg (cfg);
4761         int high2_reg = alloc_preg (cfg);
4762         int realidx1_reg = alloc_preg (cfg);
4763         int realidx2_reg = alloc_preg (cfg);
4764         int sum_reg = alloc_preg (cfg);
4765         int index1, index2, tmpreg;
4766         MonoInst *ins;
4767         guint32 size;
4768
4769         mono_class_init (klass);
4770         size = mono_class_array_element_size (klass);
4771
4772         index1 = index_ins1->dreg;
4773         index2 = index_ins2->dreg;
4774
4775 #if SIZEOF_REGISTER == 8
4776         /* The array reg is 64 bits but the index reg is only 32 */
4777         if (COMPILE_LLVM (cfg)) {
4778                 /* Not needed */
4779         } else {
4780                 tmpreg = alloc_preg (cfg);
4781                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4782                 index1 = tmpreg;
4783                 tmpreg = alloc_preg (cfg);
4784                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4785                 index2 = tmpreg;
4786         }
4787 #else
4788         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4789         tmpreg = -1;
4790 #endif
4791
4792         /* range checking */
4793         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4794                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4795
4796         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4797                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4798         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4799         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4800                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4801         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4802         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4803
4804         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4805                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4806         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4807         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4808                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4809         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4810         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4811
4812         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4813         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4814         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4815         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4816         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4817
4818         ins->type = STACK_MP;
4819         ins->klass = klass;
4820         MONO_ADD_INS (cfg->cbb, ins);
4821
4822         return ins;
4823 }
4824 #endif
4825
4826 static MonoInst*
4827 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4828 {
4829         int rank;
4830         MonoInst *addr;
4831         MonoMethod *addr_method;
4832         int element_size;
4833
4834         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4835
4836         if (rank == 1)
4837                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4838
4839 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4840         /* emit_ldelema_2 depends on OP_LMUL */
4841         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4842                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4843         }
4844 #endif
4845
4846         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4847         addr_method = mono_marshal_get_array_address (rank, element_size);
4848         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4849
4850         return addr;
4851 }
4852
4853 static MonoBreakPolicy
4854 always_insert_breakpoint (MonoMethod *method)
4855 {
4856         return MONO_BREAK_POLICY_ALWAYS;
4857 }
4858
4859 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4860
4861 /**
4862  * mono_set_break_policy:
4863  * policy_callback: the new callback function
4864  *
4865  * Allow embedders to decide wherther to actually obey breakpoint instructions
4866  * (both break IL instructions and Debugger.Break () method calls), for example
4867  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4868  * untrusted or semi-trusted code.
4869  *
4870  * @policy_callback will be called every time a break point instruction needs to
4871  * be inserted with the method argument being the method that calls Debugger.Break()
4872  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4873  * if it wants the breakpoint to not be effective in the given method.
4874  * #MONO_BREAK_POLICY_ALWAYS is the default.
4875  */
4876 void
4877 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4878 {
4879         if (policy_callback)
4880                 break_policy_func = policy_callback;
4881         else
4882                 break_policy_func = always_insert_breakpoint;
4883 }
4884
4885 static gboolean
4886 should_insert_brekpoint (MonoMethod *method) {
4887         switch (break_policy_func (method)) {
4888         case MONO_BREAK_POLICY_ALWAYS:
4889                 return TRUE;
4890         case MONO_BREAK_POLICY_NEVER:
4891                 return FALSE;
4892         case MONO_BREAK_POLICY_ON_DBG:
4893                 g_warning ("mdb no longer supported");
4894                 return FALSE;
4895         default:
4896                 g_warning ("Incorrect value returned from break policy callback");
4897                 return FALSE;
4898         }
4899 }
4900
4901 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4902 static MonoInst*
4903 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4904 {
4905         MonoInst *addr, *store, *load;
4906         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4907
4908         /* the bounds check is already done by the callers */
4909         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4910         if (is_set) {
4911                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4912                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4913                 if (mini_type_is_reference (cfg, fsig->params [2]))
4914                         emit_write_barrier (cfg, addr, load);
4915         } else {
4916                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4917                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4918         }
4919         return store;
4920 }
4921
4922
4923 static gboolean
4924 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4925 {
4926         return mini_type_is_reference (cfg, &klass->byval_arg);
4927 }
4928
4929 static MonoInst*
4930 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4931 {
4932         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4933                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
4934                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4935                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4936                 MonoInst *iargs [3];
4937
4938                 if (!helper->slot)
4939                         mono_class_setup_vtable (obj_array);
4940                 g_assert (helper->slot);
4941
4942                 if (sp [0]->type != STACK_OBJ)
4943                         return NULL;
4944                 if (sp [2]->type != STACK_OBJ)
4945                         return NULL;
4946
4947                 iargs [2] = sp [2];
4948                 iargs [1] = sp [1];
4949                 iargs [0] = sp [0];
4950
4951                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4952         } else {
4953                 MonoInst *ins;
4954
4955                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4956                         MonoInst *addr;
4957
4958                         // FIXME-VT: OP_ICONST optimization
4959                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4960                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4961                         ins->opcode = OP_STOREV_MEMBASE;
4962                 } else if (sp [1]->opcode == OP_ICONST) {
4963                         int array_reg = sp [0]->dreg;
4964                         int index_reg = sp [1]->dreg;
4965                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
4966
4967                         if (safety_checks)
4968                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4969                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4970                 } else {
4971                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4972                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4973                         if (generic_class_is_reference_type (cfg, klass))
4974                                 emit_write_barrier (cfg, addr, sp [2]);
4975                 }
4976                 return ins;
4977         }
4978 }
4979
4980 static MonoInst*
4981 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4982 {
4983         MonoClass *eklass;
4984         
4985         if (is_set)
4986                 eklass = mono_class_from_mono_type (fsig->params [2]);
4987         else
4988                 eklass = mono_class_from_mono_type (fsig->ret);
4989
4990
4991         if (is_set) {
4992                 return emit_array_store (cfg, eklass, args, FALSE);
4993         } else {
4994                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4995                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4996                 return ins;
4997         }
4998 }
4999
5000 static MonoInst*
5001 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5002 {
5003 #ifdef MONO_ARCH_SIMD_INTRINSICS
5004         MonoInst *ins = NULL;
5005
5006         if (cfg->opt & MONO_OPT_SIMD) {
5007                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5008                 if (ins)
5009                         return ins;
5010         }
5011 #endif
5012
5013         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5014 }
5015
5016 static MonoInst*
5017 emit_memory_barrier (MonoCompile *cfg, int kind)
5018 {
5019         MonoInst *ins = NULL;
5020         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5021         MONO_ADD_INS (cfg->cbb, ins);
5022         ins->backend.memory_barrier_kind = kind;
5023
5024         return ins;
5025 }
5026
5027 static MonoInst*
5028 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5029 {
5030         MonoInst *ins = NULL;
5031         int opcode = 0;
5032
5033         /* The LLVM backend supports these intrinsics */
5034         if (cmethod->klass == mono_defaults.math_class) {
5035                 if (strcmp (cmethod->name, "Sin") == 0) {
5036                         opcode = OP_SIN;
5037                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5038                         opcode = OP_COS;
5039                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5040                         opcode = OP_SQRT;
5041                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5042                         opcode = OP_ABS;
5043                 }
5044
5045                 if (opcode) {
5046                         MONO_INST_NEW (cfg, ins, opcode);
5047                         ins->type = STACK_R8;
5048                         ins->dreg = mono_alloc_freg (cfg);
5049                         ins->sreg1 = args [0]->dreg;
5050                         MONO_ADD_INS (cfg->cbb, ins);
5051                 }
5052
5053                 opcode = 0;
5054                 if (cfg->opt & MONO_OPT_CMOV) {
5055                         if (strcmp (cmethod->name, "Min") == 0) {
5056                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5057                                         opcode = OP_IMIN;
5058                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5059                                         opcode = OP_IMIN_UN;
5060                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5061                                         opcode = OP_LMIN;
5062                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5063                                         opcode = OP_LMIN_UN;
5064                         } else if (strcmp (cmethod->name, "Max") == 0) {
5065                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5066                                         opcode = OP_IMAX;
5067                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5068                                         opcode = OP_IMAX_UN;
5069                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5070                                         opcode = OP_LMAX;
5071                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5072                                         opcode = OP_LMAX_UN;
5073                         }
5074                 }
5075
5076                 if (opcode) {
5077                         MONO_INST_NEW (cfg, ins, opcode);
5078                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5079                         ins->dreg = mono_alloc_ireg (cfg);
5080                         ins->sreg1 = args [0]->dreg;
5081                         ins->sreg2 = args [1]->dreg;
5082                         MONO_ADD_INS (cfg->cbb, ins);
5083                 }
5084         }
5085
5086         return ins;
5087 }
5088
5089 static MonoInst*
5090 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5091 {
5092         if (cmethod->klass == mono_defaults.array_class) {
5093                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5094                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5095                 if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5096                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5097         }
5098
5099         return NULL;
5100 }
5101
5102 static MonoInst*
5103 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5104 {
5105         MonoInst *ins = NULL;
5106         
5107         static MonoClass *runtime_helpers_class = NULL;
5108         if (! runtime_helpers_class)
5109                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5110                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5111
5112         if (cmethod->klass == mono_defaults.string_class) {
5113                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5114                         int dreg = alloc_ireg (cfg);
5115                         int index_reg = alloc_preg (cfg);
5116                         int mult_reg = alloc_preg (cfg);
5117                         int add_reg = alloc_preg (cfg);
5118
5119 #if SIZEOF_REGISTER == 8
5120                         /* The array reg is 64 bits but the index reg is only 32 */
5121                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5122 #else
5123                         index_reg = args [1]->dreg;
5124 #endif  
5125                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5126
5127 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5128                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5129                         add_reg = ins->dreg;
5130                         /* Avoid a warning */
5131                         mult_reg = 0;
5132                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5133                                                                    add_reg, 0);
5134 #else
5135                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5136                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5137                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5138                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5139 #endif
5140                         type_from_op (ins, NULL, NULL);
5141                         return ins;
5142                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5143                         int dreg = alloc_ireg (cfg);
5144                         /* Decompose later to allow more optimizations */
5145                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5146                         ins->type = STACK_I4;
5147                         ins->flags |= MONO_INST_FAULT;
5148                         cfg->cbb->has_array_access = TRUE;
5149                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5150
5151                         return ins;
5152                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5153                         int mult_reg = alloc_preg (cfg);
5154                         int add_reg = alloc_preg (cfg);
5155
5156                         /* The corlib functions check for oob already. */
5157                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5158                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5159                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5160                         return cfg->cbb->last_ins;
5161                 } else 
5162                         return NULL;
5163         } else if (cmethod->klass == mono_defaults.object_class) {
5164
5165                 if (strcmp (cmethod->name, "GetType") == 0) {
5166                         int dreg = alloc_ireg_ref (cfg);
5167                         int vt_reg = alloc_preg (cfg);
5168                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5169                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5170                         type_from_op (ins, NULL, NULL);
5171
5172                         return ins;
5173 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5174                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5175                         int dreg = alloc_ireg (cfg);
5176                         int t1 = alloc_ireg (cfg);
5177         
5178                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5179                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5180                         ins->type = STACK_I4;
5181
5182                         return ins;
5183 #endif
5184                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5185                         MONO_INST_NEW (cfg, ins, OP_NOP);
5186                         MONO_ADD_INS (cfg->cbb, ins);
5187                         return ins;
5188                 } else
5189                         return NULL;
5190         } else if (cmethod->klass == mono_defaults.array_class) {
5191                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5192                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5193
5194 #ifndef MONO_BIG_ARRAYS
5195                 /*
5196                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5197                  * Array methods.
5198                  */
5199                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5200                         int dreg = alloc_ireg (cfg);
5201                         int bounds_reg = alloc_ireg_mp (cfg);
5202                         MonoBasicBlock *end_bb, *szarray_bb;
5203                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5204
5205                         NEW_BBLOCK (cfg, end_bb);
5206                         NEW_BBLOCK (cfg, szarray_bb);
5207
5208                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5209                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5210                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5211                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5212                         /* Non-szarray case */
5213                         if (get_length)
5214                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5215                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5216                         else
5217                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5218                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5219                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5220                         MONO_START_BB (cfg, szarray_bb);
5221                         /* Szarray case */
5222                         if (get_length)
5223                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5224                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5225                         else
5226                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5227                         MONO_START_BB (cfg, end_bb);
5228
5229                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5230                         ins->type = STACK_I4;
5231                         
5232                         return ins;
5233                 }
5234 #endif
5235
5236                 if (cmethod->name [0] != 'g')
5237                         return NULL;
5238
5239                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5240                         int dreg = alloc_ireg (cfg);
5241                         int vtable_reg = alloc_preg (cfg);
5242                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5243                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5244                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5245                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5246                         type_from_op (ins, NULL, NULL);
5247
5248                         return ins;
5249                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5250                         int dreg = alloc_ireg (cfg);
5251
5252                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5253                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5254                         type_from_op (ins, NULL, NULL);
5255
5256                         return ins;
5257                 } else
5258                         return NULL;
5259         } else if (cmethod->klass == runtime_helpers_class) {
5260
5261                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5262                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5263                         return ins;
5264                 } else
5265                         return NULL;
5266         } else if (cmethod->klass == mono_defaults.thread_class) {
5267                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5268                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5269                         MONO_ADD_INS (cfg->cbb, ins);
5270                         return ins;
5271                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5272                         return emit_memory_barrier (cfg, FullBarrier);
5273                 }
5274         } else if (cmethod->klass == mono_defaults.monitor_class) {
5275
5276                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5277 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5278                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5279                         MonoMethod *fast_method = NULL;
5280
5281                         /* Avoid infinite recursion */
5282                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5283                                 return NULL;
5284                                 
5285                         fast_method = mono_monitor_get_fast_path (cmethod);
5286                         if (!fast_method)
5287                                 return NULL;
5288
5289                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5290                 }
5291 #endif
5292
5293 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5294                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5295                         MonoCallInst *call;
5296
5297                         if (COMPILE_LLVM (cfg)) {
5298                                 /* 
5299                                  * Pass the argument normally, the LLVM backend will handle the
5300                                  * calling convention problems.
5301                                  */
5302                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5303                         } else {
5304                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5305                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5306                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5307                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5308                         }
5309
5310                         return (MonoInst*)call;
5311                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5312                         MonoCallInst *call;
5313
5314                         if (COMPILE_LLVM (cfg)) {
5315                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5316                         } else {
5317                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5318                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5319                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5320                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5321                         }
5322
5323                         return (MonoInst*)call;
5324                 }
5325 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5326                 {
5327                 MonoMethod *fast_method = NULL;
5328
5329                 /* Avoid infinite recursion */
5330                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5331                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5332                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5333                         return NULL;
5334
5335                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5336                                 strcmp (cmethod->name, "Exit") == 0)
5337                         fast_method = mono_monitor_get_fast_path (cmethod);
5338                 if (!fast_method)
5339                         return NULL;
5340
5341                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5342                 }
5343 #endif
5344         } else if (cmethod->klass->image == mono_defaults.corlib &&
5345                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5346                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5347                 ins = NULL;
5348
5349 #if SIZEOF_REGISTER == 8
5350                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5351                         /* 64 bit reads are already atomic */
5352                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5353                         ins->dreg = mono_alloc_preg (cfg);
5354                         ins->inst_basereg = args [0]->dreg;
5355                         ins->inst_offset = 0;
5356                         MONO_ADD_INS (cfg->cbb, ins);
5357                 }
5358 #endif
5359
5360 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5361                 if (strcmp (cmethod->name, "Increment") == 0) {
5362                         MonoInst *ins_iconst;
5363                         guint32 opcode = 0;
5364
5365                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5366                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5367                                 cfg->has_atomic_add_new_i4 = TRUE;
5368                         }
5369 #if SIZEOF_REGISTER == 8
5370                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5371                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5372 #endif
5373                         if (opcode) {
5374                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5375                                 ins_iconst->inst_c0 = 1;
5376                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5377                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5378
5379                                 MONO_INST_NEW (cfg, ins, opcode);
5380                                 ins->dreg = mono_alloc_ireg (cfg);
5381                                 ins->inst_basereg = args [0]->dreg;
5382                                 ins->inst_offset = 0;
5383                                 ins->sreg2 = ins_iconst->dreg;
5384                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5385                                 MONO_ADD_INS (cfg->cbb, ins);
5386                         }
5387                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5388                         MonoInst *ins_iconst;
5389                         guint32 opcode = 0;
5390
5391                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5392                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5393                                 cfg->has_atomic_add_new_i4 = TRUE;
5394                         }
5395 #if SIZEOF_REGISTER == 8
5396                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5397                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5398 #endif
5399                         if (opcode) {
5400                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5401                                 ins_iconst->inst_c0 = -1;
5402                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5403                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5404
5405                                 MONO_INST_NEW (cfg, ins, opcode);
5406                                 ins->dreg = mono_alloc_ireg (cfg);
5407                                 ins->inst_basereg = args [0]->dreg;
5408                                 ins->inst_offset = 0;
5409                                 ins->sreg2 = ins_iconst->dreg;
5410                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5411                                 MONO_ADD_INS (cfg->cbb, ins);
5412                         }
5413                 } else if (strcmp (cmethod->name, "Add") == 0) {
5414                         guint32 opcode = 0;
5415
5416                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5417                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5418                                 cfg->has_atomic_add_new_i4 = TRUE;
5419                         }
5420 #if SIZEOF_REGISTER == 8
5421                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5422                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5423 #endif
5424
5425                         if (opcode) {
5426                                 MONO_INST_NEW (cfg, ins, opcode);
5427                                 ins->dreg = mono_alloc_ireg (cfg);
5428                                 ins->inst_basereg = args [0]->dreg;
5429                                 ins->inst_offset = 0;
5430                                 ins->sreg2 = args [1]->dreg;
5431                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5432                                 MONO_ADD_INS (cfg->cbb, ins);
5433                         }
5434                 }
5435 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5436
5437 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5438                 if (strcmp (cmethod->name, "Exchange") == 0) {
5439                         guint32 opcode;
5440                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5441
5442                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5443                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5444                                 cfg->has_atomic_exchange_i4 = TRUE;
5445                         }
5446 #if SIZEOF_REGISTER == 8
5447                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5448                                         (fsig->params [0]->type == MONO_TYPE_I))
5449                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5450 #else
5451                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5452                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5453                                 cfg->has_atomic_exchange_i4 = TRUE;
5454                         }
5455 #endif
5456                         else
5457                                 return NULL;
5458
5459                         MONO_INST_NEW (cfg, ins, opcode);
5460                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5461                         ins->inst_basereg = args [0]->dreg;
5462                         ins->inst_offset = 0;
5463                         ins->sreg2 = args [1]->dreg;
5464                         MONO_ADD_INS (cfg->cbb, ins);
5465
5466                         switch (fsig->params [0]->type) {
5467                         case MONO_TYPE_I4:
5468                                 ins->type = STACK_I4;
5469                                 break;
5470                         case MONO_TYPE_I8:
5471                         case MONO_TYPE_I:
5472                                 ins->type = STACK_I8;
5473                                 break;
5474                         case MONO_TYPE_OBJECT:
5475                                 ins->type = STACK_OBJ;
5476                                 break;
5477                         default:
5478                                 g_assert_not_reached ();
5479                         }
5480
5481                         if (cfg->gen_write_barriers && is_ref)
5482                                 emit_write_barrier (cfg, args [0], args [1]);
5483                 }
5484 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5485  
5486 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5487                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5488                         int size = 0;
5489                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5490                         if (fsig->params [1]->type == MONO_TYPE_I4)
5491                                 size = 4;
5492                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5493                                 size = sizeof (gpointer);
5494                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5495                                 size = 8;
5496                         if (size == 4) {
5497                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5498                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5499                                 ins->sreg1 = args [0]->dreg;
5500                                 ins->sreg2 = args [1]->dreg;
5501                                 ins->sreg3 = args [2]->dreg;
5502                                 ins->type = STACK_I4;
5503                                 MONO_ADD_INS (cfg->cbb, ins);
5504                         } else if (size == 8) {
5505                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5506                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5507                                 ins->sreg1 = args [0]->dreg;
5508                                 ins->sreg2 = args [1]->dreg;
5509                                 ins->sreg3 = args [2]->dreg;
5510                                 ins->type = STACK_I8;
5511                                 MONO_ADD_INS (cfg->cbb, ins);
5512                         } else {
5513                                 /* g_assert_not_reached (); */
5514                         }
5515                         if (cfg->gen_write_barriers && is_ref)
5516                                 emit_write_barrier (cfg, args [0], args [1]);
5517                 }
5518 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5519
5520                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5521                         ins = emit_memory_barrier (cfg, FullBarrier);
5522
5523                 if (ins)
5524                         return ins;
5525         } else if (cmethod->klass->image == mono_defaults.corlib) {
5526                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5527                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5528                         if (should_insert_brekpoint (cfg->method)) {
5529                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5530                         } else {
5531                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5532                                 MONO_ADD_INS (cfg->cbb, ins);
5533                         }
5534                         return ins;
5535                 }
5536                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5537                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5538 #ifdef TARGET_WIN32
5539                         EMIT_NEW_ICONST (cfg, ins, 1);
5540 #else
5541                         EMIT_NEW_ICONST (cfg, ins, 0);
5542 #endif
5543                         return ins;
5544                 }
5545         } else if (cmethod->klass == mono_defaults.math_class) {
5546                 /* 
5547                  * There is general branches code for Min/Max, but it does not work for 
5548                  * all inputs:
5549                  * http://everything2.com/?node_id=1051618
5550                  */
5551         } 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)) {
5552 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5553                 MonoInst *pi;
5554                 MonoJumpInfoToken *ji;
5555                 MonoString *s;
5556
5557                 cfg->disable_llvm = TRUE;
5558
5559                 if (args [0]->opcode == OP_GOT_ENTRY) {
5560                         pi = args [0]->inst_p1;
5561                         g_assert (pi->opcode == OP_PATCH_INFO);
5562                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5563                         ji = pi->inst_p0;
5564                 } else {
5565                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5566                         ji = args [0]->inst_p0;
5567                 }
5568
5569                 NULLIFY_INS (args [0]);
5570
5571                 // FIXME: Ugly
5572                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5573                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5574                 ins->dreg = mono_alloc_ireg (cfg);
5575                 // FIXME: Leaks
5576                 ins->inst_p0 = mono_string_to_utf8 (s);
5577                 MONO_ADD_INS (cfg->cbb, ins);
5578                 return ins;
5579 #endif
5580         }
5581
5582 #ifdef MONO_ARCH_SIMD_INTRINSICS
5583         if (cfg->opt & MONO_OPT_SIMD) {
5584                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5585                 if (ins)
5586                         return ins;
5587         }
5588 #endif
5589
5590         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5591         if (ins)
5592                 return ins;
5593
5594         if (COMPILE_LLVM (cfg)) {
5595                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5596                 if (ins)
5597                         return ins;
5598         }
5599
5600         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5601 }
5602
5603 /*
5604  * This entry point could be used later for arbitrary method
5605  * redirection.
5606  */
5607 inline static MonoInst*
5608 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5609                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5610 {
5611         if (method->klass == mono_defaults.string_class) {
5612                 /* managed string allocation support */
5613                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5614                         MonoInst *iargs [2];
5615                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5616                         MonoMethod *managed_alloc = NULL;
5617
5618                         g_assert (vtable); /*Should not fail since it System.String*/
5619 #ifndef MONO_CROSS_COMPILE
5620                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5621 #endif
5622                         if (!managed_alloc)
5623                                 return NULL;
5624                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5625                         iargs [1] = args [0];
5626                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5627                 }
5628         }
5629         return NULL;
5630 }
5631
5632 static void
5633 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5634 {
5635         MonoInst *store, *temp;
5636         int i;
5637
5638         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5639                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5640
5641                 /*
5642                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5643                  * would be different than the MonoInst's used to represent arguments, and
5644                  * the ldelema implementation can't deal with that.
5645                  * Solution: When ldelema is used on an inline argument, create a var for 
5646                  * it, emit ldelema on that var, and emit the saving code below in
5647                  * inline_method () if needed.
5648                  */
5649                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5650                 cfg->args [i] = temp;
5651                 /* This uses cfg->args [i] which is set by the preceeding line */
5652                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5653                 store->cil_code = sp [0]->cil_code;
5654                 sp++;
5655         }
5656 }
5657
5658 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5659 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5660
5661 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5662 static gboolean
5663 check_inline_called_method_name_limit (MonoMethod *called_method)
5664 {
5665         int strncmp_result;
5666         static const char *limit = NULL;
5667         
5668         if (limit == NULL) {
5669                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5670
5671                 if (limit_string != NULL)
5672                         limit = limit_string;
5673                 else
5674                         limit = "";
5675         }
5676
5677         if (limit [0] != '\0') {
5678                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5679
5680                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5681                 g_free (called_method_name);
5682         
5683                 //return (strncmp_result <= 0);
5684                 return (strncmp_result == 0);
5685         } else {
5686                 return TRUE;
5687         }
5688 }
5689 #endif
5690
5691 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5692 static gboolean
5693 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5694 {
5695         int strncmp_result;
5696         static const char *limit = NULL;
5697         
5698         if (limit == NULL) {
5699                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5700                 if (limit_string != NULL) {
5701                         limit = limit_string;
5702                 } else {
5703                         limit = "";
5704                 }
5705         }
5706
5707         if (limit [0] != '\0') {
5708                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5709
5710                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5711                 g_free (caller_method_name);
5712         
5713                 //return (strncmp_result <= 0);
5714                 return (strncmp_result == 0);
5715         } else {
5716                 return TRUE;
5717         }
5718 }
5719 #endif
5720
5721 static void
5722 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5723 {
5724         static double r8_0 = 0.0;
5725         MonoInst *ins;
5726         int t;
5727
5728         rtype = mini_replace_type (rtype);
5729         t = rtype->type;
5730
5731         if (rtype->byref) {
5732                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5733         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5734                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5735         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5736                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5737         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5738                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5739                 ins->type = STACK_R8;
5740                 ins->inst_p0 = (void*)&r8_0;
5741                 ins->dreg = dreg;
5742                 MONO_ADD_INS (cfg->cbb, ins);
5743         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5744                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5745                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5746         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5747                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5748         } else {
5749                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5750         }
5751 }
5752
5753 static void
5754 emit_init_local (MonoCompile *cfg, int local, MonoType *type)
5755 {
5756         MonoInst *var = cfg->locals [local];
5757         if (COMPILE_SOFT_FLOAT (cfg)) {
5758                 MonoInst *store;
5759                 int reg = alloc_dreg (cfg, var->type);
5760                 emit_init_rvar (cfg, reg, type);
5761                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5762         } else {
5763                 emit_init_rvar (cfg, var->dreg, type);
5764         }
5765 }
5766
5767 static int
5768 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5769                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5770 {
5771         MonoInst *ins, *rvar = NULL;
5772         MonoMethodHeader *cheader;
5773         MonoBasicBlock *ebblock, *sbblock;
5774         int i, costs;
5775         MonoMethod *prev_inlined_method;
5776         MonoInst **prev_locals, **prev_args;
5777         MonoType **prev_arg_types;
5778         guint prev_real_offset;
5779         GHashTable *prev_cbb_hash;
5780         MonoBasicBlock **prev_cil_offset_to_bb;
5781         MonoBasicBlock *prev_cbb;
5782         unsigned char* prev_cil_start;
5783         guint32 prev_cil_offset_to_bb_len;
5784         MonoMethod *prev_current_method;
5785         MonoGenericContext *prev_generic_context;
5786         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5787
5788         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5789
5790 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5791         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5792                 return 0;
5793 #endif
5794 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5795         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5796                 return 0;
5797 #endif
5798
5799         if (cfg->verbose_level > 2)
5800                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5801
5802         if (!cmethod->inline_info) {
5803                 cfg->stat_inlineable_methods++;
5804                 cmethod->inline_info = 1;
5805         }
5806
5807         /* allocate local variables */
5808         cheader = mono_method_get_header (cmethod);
5809
5810         if (cheader == NULL || mono_loader_get_last_error ()) {
5811                 MonoLoaderError *error = mono_loader_get_last_error ();
5812
5813                 if (cheader)
5814                         mono_metadata_free_mh (cheader);
5815                 if (inline_always && error)
5816                         mono_cfg_set_exception (cfg, error->exception_type);
5817
5818                 mono_loader_clear_error ();
5819                 return 0;
5820         }
5821
5822         /*Must verify before creating locals as it can cause the JIT to assert.*/
5823         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5824                 mono_metadata_free_mh (cheader);
5825                 return 0;
5826         }
5827
5828         /* allocate space to store the return value */
5829         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5830                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5831         }
5832
5833         prev_locals = cfg->locals;
5834         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5835         for (i = 0; i < cheader->num_locals; ++i)
5836                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5837
5838         /* allocate start and end blocks */
5839         /* This is needed so if the inline is aborted, we can clean up */
5840         NEW_BBLOCK (cfg, sbblock);
5841         sbblock->real_offset = real_offset;
5842
5843         NEW_BBLOCK (cfg, ebblock);
5844         ebblock->block_num = cfg->num_bblocks++;
5845         ebblock->real_offset = real_offset;
5846
5847         prev_args = cfg->args;
5848         prev_arg_types = cfg->arg_types;
5849         prev_inlined_method = cfg->inlined_method;
5850         cfg->inlined_method = cmethod;
5851         cfg->ret_var_set = FALSE;
5852         cfg->inline_depth ++;
5853         prev_real_offset = cfg->real_offset;
5854         prev_cbb_hash = cfg->cbb_hash;
5855         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
5856         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
5857         prev_cil_start = cfg->cil_start;
5858         prev_cbb = cfg->cbb;
5859         prev_current_method = cfg->current_method;
5860         prev_generic_context = cfg->generic_context;
5861         prev_ret_var_set = cfg->ret_var_set;
5862
5863         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
5864                 virtual = TRUE;
5865
5866         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
5867
5868         ret_var_set = cfg->ret_var_set;
5869
5870         cfg->inlined_method = prev_inlined_method;
5871         cfg->real_offset = prev_real_offset;
5872         cfg->cbb_hash = prev_cbb_hash;
5873         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
5874         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
5875         cfg->cil_start = prev_cil_start;
5876         cfg->locals = prev_locals;
5877         cfg->args = prev_args;
5878         cfg->arg_types = prev_arg_types;
5879         cfg->current_method = prev_current_method;
5880         cfg->generic_context = prev_generic_context;
5881         cfg->ret_var_set = prev_ret_var_set;
5882         cfg->inline_depth --;
5883
5884         if ((costs >= 0 && costs < 60) || inline_always) {
5885                 if (cfg->verbose_level > 2)
5886                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5887                 
5888                 cfg->stat_inlined_methods++;
5889
5890                 /* always add some code to avoid block split failures */
5891                 MONO_INST_NEW (cfg, ins, OP_NOP);
5892                 MONO_ADD_INS (prev_cbb, ins);
5893
5894                 prev_cbb->next_bb = sbblock;
5895                 link_bblock (cfg, prev_cbb, sbblock);
5896
5897                 /* 
5898                  * Get rid of the begin and end bblocks if possible to aid local
5899                  * optimizations.
5900                  */
5901                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
5902
5903                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
5904                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
5905
5906                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
5907                         MonoBasicBlock *prev = ebblock->in_bb [0];
5908                         mono_merge_basic_blocks (cfg, prev, ebblock);
5909                         cfg->cbb = prev;
5910                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
5911                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
5912                                 cfg->cbb = prev_cbb;
5913                         }
5914                 } else {
5915                         /* 
5916                          * Its possible that the rvar is set in some prev bblock, but not in others.
5917                          * (#1835).
5918                          */
5919                         if (rvar) {
5920                                 MonoBasicBlock *bb;
5921
5922                                 for (i = 0; i < ebblock->in_count; ++i) {
5923                                         bb = ebblock->in_bb [i];
5924
5925                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
5926                                                 cfg->cbb = bb;
5927
5928                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
5929                                         }
5930                                 }
5931                         }
5932
5933                         cfg->cbb = ebblock;
5934                 }
5935
5936                 if (rvar) {
5937                         /*
5938                          * If the inlined method contains only a throw, then the ret var is not 
5939                          * set, so set it to a dummy value.
5940                          */
5941                         if (!ret_var_set)
5942                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
5943
5944                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
5945                         *sp++ = ins;
5946                 }
5947                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5948                 return costs + 1;
5949         } else {
5950                 if (cfg->verbose_level > 2)
5951                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
5952                 cfg->exception_type = MONO_EXCEPTION_NONE;
5953                 mono_loader_clear_error ();
5954
5955                 /* This gets rid of the newly added bblocks */
5956                 cfg->cbb = prev_cbb;
5957         }
5958         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5959         return 0;
5960 }
5961
5962 /*
5963  * Some of these comments may well be out-of-date.
5964  * Design decisions: we do a single pass over the IL code (and we do bblock 
5965  * splitting/merging in the few cases when it's required: a back jump to an IL
5966  * address that was not already seen as bblock starting point).
5967  * Code is validated as we go (full verification is still better left to metadata/verify.c).
5968  * Complex operations are decomposed in simpler ones right away. We need to let the 
5969  * arch-specific code peek and poke inside this process somehow (except when the 
5970  * optimizations can take advantage of the full semantic info of coarse opcodes).
5971  * All the opcodes of the form opcode.s are 'normalized' to opcode.
5972  * MonoInst->opcode initially is the IL opcode or some simplification of that 
5973  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
5974  * opcode with value bigger than OP_LAST.
5975  * At this point the IR can be handed over to an interpreter, a dumb code generator
5976  * or to the optimizing code generator that will translate it to SSA form.
5977  *
5978  * Profiling directed optimizations.
5979  * We may compile by default with few or no optimizations and instrument the code
5980  * or the user may indicate what methods to optimize the most either in a config file
5981  * or through repeated runs where the compiler applies offline the optimizations to 
5982  * each method and then decides if it was worth it.
5983  */
5984
5985 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
5986 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
5987 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
5988 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
5989 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
5990 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
5991 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
5992 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
5993
5994 /* offset from br.s -> br like opcodes */
5995 #define BIG_BRANCH_OFFSET 13
5996
5997 static gboolean
5998 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
5999 {
6000         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6001
6002         return b == NULL || b == bb;
6003 }
6004
6005 static int
6006 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6007 {
6008         unsigned char *ip = start;
6009         unsigned char *target;
6010         int i;
6011         guint cli_addr;
6012         MonoBasicBlock *bblock;
6013         const MonoOpcode *opcode;
6014
6015         while (ip < end) {
6016                 cli_addr = ip - start;
6017                 i = mono_opcode_value ((const guint8 **)&ip, end);
6018                 if (i < 0)
6019                         UNVERIFIED;
6020                 opcode = &mono_opcodes [i];
6021                 switch (opcode->argument) {
6022                 case MonoInlineNone:
6023                         ip++; 
6024                         break;
6025                 case MonoInlineString:
6026                 case MonoInlineType:
6027                 case MonoInlineField:
6028                 case MonoInlineMethod:
6029                 case MonoInlineTok:
6030                 case MonoInlineSig:
6031                 case MonoShortInlineR:
6032                 case MonoInlineI:
6033                         ip += 5;
6034                         break;
6035                 case MonoInlineVar:
6036                         ip += 3;
6037                         break;
6038                 case MonoShortInlineVar:
6039                 case MonoShortInlineI:
6040                         ip += 2;
6041                         break;
6042                 case MonoShortInlineBrTarget:
6043                         target = start + cli_addr + 2 + (signed char)ip [1];
6044                         GET_BBLOCK (cfg, bblock, target);
6045                         ip += 2;
6046                         if (ip < end)
6047                                 GET_BBLOCK (cfg, bblock, ip);
6048                         break;
6049                 case MonoInlineBrTarget:
6050                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6051                         GET_BBLOCK (cfg, bblock, target);
6052                         ip += 5;
6053                         if (ip < end)
6054                                 GET_BBLOCK (cfg, bblock, ip);
6055                         break;
6056                 case MonoInlineSwitch: {
6057                         guint32 n = read32 (ip + 1);
6058                         guint32 j;
6059                         ip += 5;
6060                         cli_addr += 5 + 4 * n;
6061                         target = start + cli_addr;
6062                         GET_BBLOCK (cfg, bblock, target);
6063                         
6064                         for (j = 0; j < n; ++j) {
6065                                 target = start + cli_addr + (gint32)read32 (ip);
6066                                 GET_BBLOCK (cfg, bblock, target);
6067                                 ip += 4;
6068                         }
6069                         break;
6070                 }
6071                 case MonoInlineR:
6072                 case MonoInlineI8:
6073                         ip += 9;
6074                         break;
6075                 default:
6076                         g_assert_not_reached ();
6077                 }
6078
6079                 if (i == CEE_THROW) {
6080                         unsigned char *bb_start = ip - 1;
6081                         
6082                         /* Find the start of the bblock containing the throw */
6083                         bblock = NULL;
6084                         while ((bb_start >= start) && !bblock) {
6085                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6086                                 bb_start --;
6087                         }
6088                         if (bblock)
6089                                 bblock->out_of_line = 1;
6090                 }
6091         }
6092         return 0;
6093 unverified:
6094 exception_exit:
6095         *pos = ip;
6096         return 1;
6097 }
6098
6099 static inline MonoMethod *
6100 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6101 {
6102         MonoMethod *method;
6103
6104         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6105                 method = mono_method_get_wrapper_data (m, token);
6106                 if (context)
6107                         method = mono_class_inflate_generic_method (method, context);
6108         } else {
6109                 method = mono_get_method_full (m->klass->image, token, klass, context);
6110         }
6111
6112         return method;
6113 }
6114
6115 static inline MonoMethod *
6116 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6117 {
6118         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6119
6120         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6121                 return NULL;
6122
6123         return method;
6124 }
6125
6126 static inline MonoClass*
6127 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6128 {
6129         MonoClass *klass;
6130
6131         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6132                 klass = mono_method_get_wrapper_data (method, token);
6133                 if (context)
6134                         klass = mono_class_inflate_generic_class (klass, context);
6135         } else {
6136                 klass = mono_class_get_full (method->klass->image, token, context);
6137         }
6138         if (klass)
6139                 mono_class_init (klass);
6140         return klass;
6141 }
6142
6143 static inline MonoMethodSignature*
6144 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6145 {
6146         MonoMethodSignature *fsig;
6147
6148         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6149                 MonoError error;
6150
6151                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6152                 if (context) {
6153                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6154                         // FIXME:
6155                         g_assert (mono_error_ok (&error));
6156                 }
6157         } else {
6158                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6159         }
6160         return fsig;
6161 }
6162
6163 /*
6164  * Returns TRUE if the JIT should abort inlining because "callee"
6165  * is influenced by security attributes.
6166  */
6167 static
6168 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6169 {
6170         guint32 result;
6171         
6172         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6173                 return TRUE;
6174         }
6175         
6176         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6177         if (result == MONO_JIT_SECURITY_OK)
6178                 return FALSE;
6179
6180         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6181                 /* Generate code to throw a SecurityException before the actual call/link */
6182                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6183                 MonoInst *args [2];
6184
6185                 NEW_ICONST (cfg, args [0], 4);
6186                 NEW_METHODCONST (cfg, args [1], caller);
6187                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6188         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6189                  /* don't hide previous results */
6190                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6191                 cfg->exception_data = result;
6192                 return TRUE;
6193         }
6194         
6195         return FALSE;
6196 }
6197
6198 static MonoMethod*
6199 throw_exception (void)
6200 {
6201         static MonoMethod *method = NULL;
6202
6203         if (!method) {
6204                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6205                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6206         }
6207         g_assert (method);
6208         return method;
6209 }
6210
6211 static void
6212 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6213 {
6214         MonoMethod *thrower = throw_exception ();
6215         MonoInst *args [1];
6216
6217         EMIT_NEW_PCONST (cfg, args [0], ex);
6218         mono_emit_method_call (cfg, thrower, args, NULL);
6219 }
6220
6221 /*
6222  * Return the original method is a wrapper is specified. We can only access 
6223  * the custom attributes from the original method.
6224  */
6225 static MonoMethod*
6226 get_original_method (MonoMethod *method)
6227 {
6228         if (method->wrapper_type == MONO_WRAPPER_NONE)
6229                 return method;
6230
6231         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6232         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6233                 return NULL;
6234
6235         /* in other cases we need to find the original method */
6236         return mono_marshal_method_from_wrapper (method);
6237 }
6238
6239 static void
6240 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6241                                           MonoBasicBlock *bblock, unsigned char *ip)
6242 {
6243         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6244         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6245         if (ex)
6246                 emit_throw_exception (cfg, ex);
6247 }
6248
6249 static void
6250 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6251                                          MonoBasicBlock *bblock, unsigned char *ip)
6252 {
6253         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6254         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6255         if (ex)
6256                 emit_throw_exception (cfg, ex);
6257 }
6258
6259 /*
6260  * Check that the IL instructions at ip are the array initialization
6261  * sequence and return the pointer to the data and the size.
6262  */
6263 static const char*
6264 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6265 {
6266         /*
6267          * newarr[System.Int32]
6268          * dup
6269          * ldtoken field valuetype ...
6270          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6271          */
6272         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6273                 guint32 token = read32 (ip + 7);
6274                 guint32 field_token = read32 (ip + 2);
6275                 guint32 field_index = field_token & 0xffffff;
6276                 guint32 rva;
6277                 const char *data_ptr;
6278                 int size = 0;
6279                 MonoMethod *cmethod;
6280                 MonoClass *dummy_class;
6281                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6282                 int dummy_align;
6283
6284                 if (!field)
6285                         return NULL;
6286
6287                 *out_field_token = field_token;
6288
6289                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6290                 if (!cmethod)
6291                         return NULL;
6292                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6293                         return NULL;
6294                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6295                 case MONO_TYPE_BOOLEAN:
6296                 case MONO_TYPE_I1:
6297                 case MONO_TYPE_U1:
6298                         size = 1; break;
6299                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6300 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6301                 case MONO_TYPE_CHAR:
6302                 case MONO_TYPE_I2:
6303                 case MONO_TYPE_U2:
6304                         size = 2; break;
6305                 case MONO_TYPE_I4:
6306                 case MONO_TYPE_U4:
6307                 case MONO_TYPE_R4:
6308                         size = 4; break;
6309                 case MONO_TYPE_R8:
6310                 case MONO_TYPE_I8:
6311                 case MONO_TYPE_U8:
6312                         size = 8; break;
6313 #endif
6314                 default:
6315                         return NULL;
6316                 }
6317                 size *= len;
6318                 if (size > mono_type_size (field->type, &dummy_align))
6319                     return NULL;
6320                 *out_size = size;
6321                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6322                 if (!method->klass->image->dynamic) {
6323                         field_index = read32 (ip + 2) & 0xffffff;
6324                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6325                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6326                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6327                         /* for aot code we do the lookup on load */
6328                         if (aot && data_ptr)
6329                                 return GUINT_TO_POINTER (rva);
6330                 } else {
6331                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6332                         g_assert (!aot);
6333                         data_ptr = mono_field_get_data (field);
6334                 }
6335                 return data_ptr;
6336         }
6337         return NULL;
6338 }
6339
6340 static void
6341 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6342 {
6343         char *method_fname = mono_method_full_name (method, TRUE);
6344         char *method_code;
6345         MonoMethodHeader *header = mono_method_get_header (method);
6346
6347         if (header->code_size == 0)
6348                 method_code = g_strdup ("method body is empty.");
6349         else
6350                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6351         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6352         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6353         g_free (method_fname);
6354         g_free (method_code);
6355         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6356 }
6357
6358 static void
6359 set_exception_object (MonoCompile *cfg, MonoException *exception)
6360 {
6361         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6362         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6363         cfg->exception_ptr = exception;
6364 }
6365
6366 static void
6367 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6368 {
6369         MonoInst *ins;
6370         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6371         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6372                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6373                 /* Optimize reg-reg moves away */
6374                 /* 
6375                  * Can't optimize other opcodes, since sp[0] might point to
6376                  * the last ins of a decomposed opcode.
6377                  */
6378                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6379         } else {
6380                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6381         }
6382 }
6383
6384 /*
6385  * ldloca inhibits many optimizations so try to get rid of it in common
6386  * cases.
6387  */
6388 static inline unsigned char *
6389 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6390 {
6391         int local, token;
6392         MonoClass *klass;
6393         MonoType *type;
6394
6395         if (size == 1) {
6396                 local = ip [1];
6397                 ip += 2;
6398         } else {
6399                 local = read16 (ip + 2);
6400                 ip += 4;
6401         }
6402         
6403         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6404                 /* From the INITOBJ case */
6405                 token = read32 (ip + 2);
6406                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6407                 CHECK_TYPELOAD (klass);
6408                 type = mini_replace_type (&klass->byval_arg);
6409                 emit_init_local (cfg, local, type);
6410                 return ip + 6;
6411         }
6412 load_error:
6413         return NULL;
6414 }
6415
6416 static gboolean
6417 is_exception_class (MonoClass *class)
6418 {
6419         while (class) {
6420                 if (class == mono_defaults.exception_class)
6421                         return TRUE;
6422                 class = class->parent;
6423         }
6424         return FALSE;
6425 }
6426
6427 /*
6428  * is_jit_optimizer_disabled:
6429  *
6430  *   Determine whenever M's assembly has a DebuggableAttribute with the
6431  * IsJITOptimizerDisabled flag set.
6432  */
6433 static gboolean
6434 is_jit_optimizer_disabled (MonoMethod *m)
6435 {
6436         MonoAssembly *ass = m->klass->image->assembly;
6437         MonoCustomAttrInfo* attrs;
6438         static MonoClass *klass;
6439         int i;
6440         gboolean val = FALSE;
6441
6442         g_assert (ass);
6443         if (ass->jit_optimizer_disabled_inited)
6444                 return ass->jit_optimizer_disabled;
6445
6446         if (!klass)
6447                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6448         if (!klass) {
6449                 /* Linked away */
6450                 ass->jit_optimizer_disabled = FALSE;
6451                 mono_memory_barrier ();
6452                 ass->jit_optimizer_disabled_inited = TRUE;
6453                 return FALSE;
6454         }
6455
6456         attrs = mono_custom_attrs_from_assembly (ass);
6457         if (attrs) {
6458                 for (i = 0; i < attrs->num_attrs; ++i) {
6459                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6460                         const gchar *p;
6461                         int len;
6462                         MonoMethodSignature *sig;
6463
6464                         if (!attr->ctor || attr->ctor->klass != klass)
6465                                 continue;
6466                         /* Decode the attribute. See reflection.c */
6467                         len = attr->data_size;
6468                         p = (const char*)attr->data;
6469                         g_assert (read16 (p) == 0x0001);
6470                         p += 2;
6471
6472                         // FIXME: Support named parameters
6473                         sig = mono_method_signature (attr->ctor);
6474                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6475                                 continue;
6476                         /* Two boolean arguments */
6477                         p ++;
6478                         val = *p;
6479                 }
6480                 mono_custom_attrs_free (attrs);
6481         }
6482
6483         ass->jit_optimizer_disabled = val;
6484         mono_memory_barrier ();
6485         ass->jit_optimizer_disabled_inited = TRUE;
6486
6487         return val;
6488 }
6489
6490 static gboolean
6491 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6492 {
6493         gboolean supported_tail_call;
6494         int i;
6495
6496 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6497         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6498 #else
6499         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6500 #endif
6501
6502         for (i = 0; i < fsig->param_count; ++i) {
6503                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6504                         /* These can point to the current method's stack */
6505                         supported_tail_call = FALSE;
6506         }
6507         if (fsig->hasthis && cmethod->klass->valuetype)
6508                 /* this might point to the current method's stack */
6509                 supported_tail_call = FALSE;
6510         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6511                 supported_tail_call = FALSE;
6512         if (cfg->method->save_lmf)
6513                 supported_tail_call = FALSE;
6514         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6515                 supported_tail_call = FALSE;
6516         if (call_opcode != CEE_CALL)
6517                 supported_tail_call = FALSE;
6518
6519         /* Debugging support */
6520 #if 0
6521         if (supported_tail_call) {
6522                 if (!mono_debug_count ())
6523                         supported_tail_call = FALSE;
6524         }
6525 #endif
6526
6527         return supported_tail_call;
6528 }
6529
6530 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6531  * it to the thread local value based on the tls_offset field. Every other kind of access to
6532  * the field causes an assert.
6533  */
6534 static gboolean
6535 is_magic_tls_access (MonoClassField *field)
6536 {
6537         if (strcmp (field->name, "tlsdata"))
6538                 return FALSE;
6539         if (strcmp (field->parent->name, "ThreadLocal`1"))
6540                 return FALSE;
6541         return field->parent->image == mono_defaults.corlib;
6542 }
6543
6544 /* emits the code needed to access a managed tls var (like ThreadStatic)
6545  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6546  * pointer for the current thread.
6547  * Returns the MonoInst* representing the address of the tls var.
6548  */
6549 static MonoInst*
6550 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6551 {
6552         MonoInst *addr;
6553         int static_data_reg, array_reg, dreg;
6554         int offset2_reg, idx_reg;
6555         // inlined access to the tls data
6556         // idx = (offset >> 24) - 1;
6557         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6558         static_data_reg = alloc_ireg (cfg);
6559         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6560         idx_reg = alloc_ireg (cfg);
6561         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6562         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6563         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6564         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6565         array_reg = alloc_ireg (cfg);
6566         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6567         offset2_reg = alloc_ireg (cfg);
6568         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6569         dreg = alloc_ireg (cfg);
6570         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6571         return addr;
6572 }
6573
6574 /*
6575  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6576  * this address is cached per-method in cached_tls_addr.
6577  */
6578 static MonoInst*
6579 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6580 {
6581         MonoInst *load, *addr, *temp, *store, *thread_ins;
6582         MonoClassField *offset_field;
6583
6584         if (*cached_tls_addr) {
6585                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6586                 return addr;
6587         }
6588         thread_ins = mono_get_thread_intrinsic (cfg);
6589         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6590
6591         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6592         if (thread_ins) {
6593                 MONO_ADD_INS (cfg->cbb, thread_ins);
6594         } else {
6595                 MonoMethod *thread_method;
6596                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6597                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6598         }
6599         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6600         addr->klass = mono_class_from_mono_type (tls_field->type);
6601         addr->type = STACK_MP;
6602         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6603         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6604
6605         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6606         return addr;
6607 }
6608
6609 /*
6610  * mono_method_to_ir:
6611  *
6612  *   Translate the .net IL into linear IR.
6613  */
6614 int
6615 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6616                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6617                    guint inline_offset, gboolean is_virtual_call)
6618 {
6619         MonoError error;
6620         MonoInst *ins, **sp, **stack_start;
6621         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6622         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6623         MonoMethod *cmethod, *method_definition;
6624         MonoInst **arg_array;
6625         MonoMethodHeader *header;
6626         MonoImage *image;
6627         guint32 token, ins_flag;
6628         MonoClass *klass;
6629         MonoClass *constrained_call = NULL;
6630         unsigned char *ip, *end, *target, *err_pos;
6631         MonoMethodSignature *sig;
6632         MonoGenericContext *generic_context = NULL;
6633         MonoGenericContainer *generic_container = NULL;
6634         MonoType **param_types;
6635         int i, n, start_new_bblock, dreg;
6636         int num_calls = 0, inline_costs = 0;
6637         int breakpoint_id = 0;
6638         guint num_args;
6639         MonoBoolean security, pinvoke;
6640         MonoSecurityManager* secman = NULL;
6641         MonoDeclSecurityActions actions;
6642         GSList *class_inits = NULL;
6643         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6644         int context_used;
6645         gboolean init_locals, seq_points, skip_dead_blocks;
6646         gboolean disable_inline, sym_seq_points = FALSE;
6647         MonoInst *cached_tls_addr = NULL;
6648         MonoDebugMethodInfo *minfo;
6649         MonoBitSet *seq_point_locs = NULL;
6650         MonoBitSet *seq_point_set_locs = NULL;
6651
6652         disable_inline = is_jit_optimizer_disabled (method);
6653
6654         /* serialization and xdomain stuff may need access to private fields and methods */
6655         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6656         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6657         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6658         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6659         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6660         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6661
6662         dont_verify |= mono_security_smcs_hack_enabled ();
6663
6664         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6665         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6666         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6667         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6668         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6669
6670         image = method->klass->image;
6671         header = mono_method_get_header (method);
6672         if (!header) {
6673                 MonoLoaderError *error;
6674
6675                 if ((error = mono_loader_get_last_error ())) {
6676                         mono_cfg_set_exception (cfg, error->exception_type);
6677                 } else {
6678                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6679                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6680                 }
6681                 goto exception_exit;
6682         }
6683         generic_container = mono_method_get_generic_container (method);
6684         sig = mono_method_signature (method);
6685         num_args = sig->hasthis + sig->param_count;
6686         ip = (unsigned char*)header->code;
6687         cfg->cil_start = ip;
6688         end = ip + header->code_size;
6689         cfg->stat_cil_code_size += header->code_size;
6690         init_locals = header->init_locals;
6691
6692         seq_points = cfg->gen_seq_points && cfg->method == method;
6693 #ifdef PLATFORM_ANDROID
6694         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6695 #endif
6696
6697         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6698                 /* We could hit a seq point before attaching to the JIT (#8338) */
6699                 seq_points = FALSE;
6700         }
6701
6702         if (cfg->gen_seq_points && cfg->method == method) {
6703                 minfo = mono_debug_lookup_method (method);
6704                 if (minfo) {
6705                         int i, n_il_offsets;
6706                         int *il_offsets;
6707                         int *line_numbers;
6708
6709                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6710                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6711                         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);
6712                         sym_seq_points = TRUE;
6713                         for (i = 0; i < n_il_offsets; ++i) {
6714                                 if (il_offsets [i] < header->code_size)
6715                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6716                         }
6717                         g_free (il_offsets);
6718                         g_free (line_numbers);
6719                 }
6720         }
6721
6722         /* 
6723          * Methods without init_locals set could cause asserts in various passes
6724          * (#497220).
6725          */
6726         init_locals = TRUE;
6727
6728         method_definition = method;
6729         while (method_definition->is_inflated) {
6730                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6731                 method_definition = imethod->declaring;
6732         }
6733
6734         /* SkipVerification is not allowed if core-clr is enabled */
6735         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6736                 dont_verify = TRUE;
6737                 dont_verify_stloc = TRUE;
6738         }
6739
6740         if (sig->is_inflated)
6741                 generic_context = mono_method_get_context (method);
6742         else if (generic_container)
6743                 generic_context = &generic_container->context;
6744         cfg->generic_context = generic_context;
6745
6746         if (!cfg->generic_sharing_context)
6747                 g_assert (!sig->has_type_parameters);
6748
6749         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6750                 g_assert (method->is_inflated);
6751                 g_assert (mono_method_get_context (method)->method_inst);
6752         }
6753         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6754                 g_assert (sig->generic_param_count);
6755
6756         if (cfg->method == method) {
6757                 cfg->real_offset = 0;
6758         } else {
6759                 cfg->real_offset = inline_offset;
6760         }
6761
6762         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6763         cfg->cil_offset_to_bb_len = header->code_size;
6764
6765         cfg->current_method = method;
6766
6767         if (cfg->verbose_level > 2)
6768                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6769
6770         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6771         if (sig->hasthis)
6772                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6773         for (n = 0; n < sig->param_count; ++n)
6774                 param_types [n + sig->hasthis] = sig->params [n];
6775         cfg->arg_types = param_types;
6776
6777         dont_inline = g_list_prepend (dont_inline, method);
6778         if (cfg->method == method) {
6779
6780                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6781                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6782
6783                 /* ENTRY BLOCK */
6784                 NEW_BBLOCK (cfg, start_bblock);
6785                 cfg->bb_entry = start_bblock;
6786                 start_bblock->cil_code = NULL;
6787                 start_bblock->cil_length = 0;
6788 #if defined(__native_client_codegen__)
6789                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6790                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6791                 MONO_ADD_INS (start_bblock, ins);
6792 #endif
6793
6794                 /* EXIT BLOCK */
6795                 NEW_BBLOCK (cfg, end_bblock);
6796                 cfg->bb_exit = end_bblock;
6797                 end_bblock->cil_code = NULL;
6798                 end_bblock->cil_length = 0;
6799                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6800                 g_assert (cfg->num_bblocks == 2);
6801
6802                 arg_array = cfg->args;
6803
6804                 if (header->num_clauses) {
6805                         cfg->spvars = g_hash_table_new (NULL, NULL);
6806                         cfg->exvars = g_hash_table_new (NULL, NULL);
6807                 }
6808                 /* handle exception clauses */
6809                 for (i = 0; i < header->num_clauses; ++i) {
6810                         MonoBasicBlock *try_bb;
6811                         MonoExceptionClause *clause = &header->clauses [i];
6812                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6813                         try_bb->real_offset = clause->try_offset;
6814                         try_bb->try_start = TRUE;
6815                         try_bb->region = ((i + 1) << 8) | clause->flags;
6816                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6817                         tblock->real_offset = clause->handler_offset;
6818                         tblock->flags |= BB_EXCEPTION_HANDLER;
6819
6820                         /*
6821                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6822                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
6823                          */
6824                         if (COMPILE_LLVM (cfg))
6825                                 link_bblock (cfg, try_bb, tblock);
6826
6827                         if (*(ip + clause->handler_offset) == CEE_POP)
6828                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6829
6830                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6831                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6832                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6833                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6834                                 MONO_ADD_INS (tblock, ins);
6835
6836                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6837                                         /* finally clauses already have a seq point */
6838                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6839                                         MONO_ADD_INS (tblock, ins);
6840                                 }
6841
6842                                 /* todo: is a fault block unsafe to optimize? */
6843                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6844                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
6845                         }
6846
6847
6848                         /*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);
6849                           while (p < end) {
6850                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
6851                           }*/
6852                         /* catch and filter blocks get the exception object on the stack */
6853                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
6854                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6855                                 MonoInst *dummy_use;
6856
6857                                 /* mostly like handle_stack_args (), but just sets the input args */
6858                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
6859                                 tblock->in_scount = 1;
6860                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6861                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6862
6863                                 /* 
6864                                  * Add a dummy use for the exvar so its liveness info will be
6865                                  * correct.
6866                                  */
6867                                 cfg->cbb = tblock;
6868                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
6869                                 
6870                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6871                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
6872                                         tblock->flags |= BB_EXCEPTION_HANDLER;
6873                                         tblock->real_offset = clause->data.filter_offset;
6874                                         tblock->in_scount = 1;
6875                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6876                                         /* The filter block shares the exvar with the handler block */
6877                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6878                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6879                                         MONO_ADD_INS (tblock, ins);
6880                                 }
6881                         }
6882
6883                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
6884                                         clause->data.catch_class &&
6885                                         cfg->generic_sharing_context &&
6886                                         mono_class_check_context_used (clause->data.catch_class)) {
6887                                 /*
6888                                  * In shared generic code with catch
6889                                  * clauses containing type variables
6890                                  * the exception handling code has to
6891                                  * be able to get to the rgctx.
6892                                  * Therefore we have to make sure that
6893                                  * the vtable/mrgctx argument (for
6894                                  * static or generic methods) or the
6895                                  * "this" argument (for non-static
6896                                  * methods) are live.
6897                                  */
6898                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6899                                                 mini_method_get_context (method)->method_inst ||
6900                                                 method->klass->valuetype) {
6901                                         mono_get_vtable_var (cfg);
6902                                 } else {
6903                                         MonoInst *dummy_use;
6904
6905                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
6906                                 }
6907                         }
6908                 }
6909         } else {
6910                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
6911                 cfg->cbb = start_bblock;
6912                 cfg->args = arg_array;
6913                 mono_save_args (cfg, sig, inline_args);
6914         }
6915
6916         /* FIRST CODE BLOCK */
6917         NEW_BBLOCK (cfg, bblock);
6918         bblock->cil_code = ip;
6919         cfg->cbb = bblock;
6920         cfg->ip = ip;
6921
6922         ADD_BBLOCK (cfg, bblock);
6923
6924         if (cfg->method == method) {
6925                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
6926                 if (breakpoint_id) {
6927                         MONO_INST_NEW (cfg, ins, OP_BREAK);
6928                         MONO_ADD_INS (bblock, ins);
6929                 }
6930         }
6931
6932         if (mono_security_cas_enabled ())
6933                 secman = mono_security_manager_get_methods ();
6934
6935         security = (secman && mono_security_method_has_declsec (method));
6936         /* at this point having security doesn't mean we have any code to generate */
6937         if (security && (cfg->method == method)) {
6938                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
6939                  * And we do not want to enter the next section (with allocation) if we
6940                  * have nothing to generate */
6941                 security = mono_declsec_get_demands (method, &actions);
6942         }
6943
6944         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
6945         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
6946         if (pinvoke) {
6947                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6948                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6949                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
6950
6951                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
6952                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6953                                 pinvoke = FALSE;
6954                         }
6955                         if (custom)
6956                                 mono_custom_attrs_free (custom);
6957
6958                         if (pinvoke) {
6959                                 custom = mono_custom_attrs_from_class (wrapped->klass);
6960                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6961                                         pinvoke = FALSE;
6962                                 }
6963                                 if (custom)
6964                                         mono_custom_attrs_free (custom);
6965                         }
6966                 } else {
6967                         /* not a P/Invoke after all */
6968                         pinvoke = FALSE;
6969                 }
6970         }
6971         
6972         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
6973                 /* we use a separate basic block for the initialization code */
6974                 NEW_BBLOCK (cfg, init_localsbb);
6975                 cfg->bb_init = init_localsbb;
6976                 init_localsbb->real_offset = cfg->real_offset;
6977                 start_bblock->next_bb = init_localsbb;
6978                 init_localsbb->next_bb = bblock;
6979                 link_bblock (cfg, start_bblock, init_localsbb);
6980                 link_bblock (cfg, init_localsbb, bblock);
6981                 
6982                 cfg->cbb = init_localsbb;
6983         } else {
6984                 start_bblock->next_bb = bblock;
6985                 link_bblock (cfg, start_bblock, bblock);
6986         }
6987
6988         if (cfg->gsharedvt && cfg->method == method) {
6989                 MonoGSharedVtMethodInfo *info;
6990                 MonoInst *var, *locals_var;
6991                 int dreg;
6992
6993                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
6994                 info->method = cfg->method;
6995                 info->count_entries = 16;
6996                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
6997                 cfg->gsharedvt_info = info;
6998
6999                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7000                 /* prevent it from being register allocated */
7001                 //var->flags |= MONO_INST_VOLATILE;
7002                 cfg->gsharedvt_info_var = var;
7003
7004                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7005                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7006
7007                 /* Allocate locals */
7008                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7009                 /* prevent it from being register allocated */
7010                 //locals_var->flags |= MONO_INST_VOLATILE;
7011                 cfg->gsharedvt_locals_var = locals_var;
7012
7013                 dreg = alloc_ireg (cfg);
7014                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7015
7016                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7017                 ins->dreg = locals_var->dreg;
7018                 ins->sreg1 = dreg;
7019                 MONO_ADD_INS (cfg->cbb, ins);
7020                 cfg->gsharedvt_locals_var_ins = ins;
7021                 
7022                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7023                 /*
7024                 if (init_locals)
7025                         ins->flags |= MONO_INST_INIT;
7026                 */
7027         }
7028
7029         /* at this point we know, if security is TRUE, that some code needs to be generated */
7030         if (security && (cfg->method == method)) {
7031                 MonoInst *args [2];
7032
7033                 cfg->stat_cas_demand_generation++;
7034
7035                 if (actions.demand.blob) {
7036                         /* Add code for SecurityAction.Demand */
7037                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7038                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7039                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7040                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7041                 }
7042                 if (actions.noncasdemand.blob) {
7043                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7044                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7045                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7046                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7047                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7048                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7049                 }
7050                 if (actions.demandchoice.blob) {
7051                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7052                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7053                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7054                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7055                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7056                 }
7057         }
7058
7059         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7060         if (pinvoke) {
7061                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7062         }
7063
7064         if (mono_security_core_clr_enabled ()) {
7065                 /* check if this is native code, e.g. an icall or a p/invoke */
7066                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7067                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7068                         if (wrapped) {
7069                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7070                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7071
7072                                 /* if this ia a native call then it can only be JITted from platform code */
7073                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7074                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7075                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7076                                                         mono_get_exception_method_access ();
7077                                                 emit_throw_exception (cfg, ex);
7078                                         }
7079                                 }
7080                         }
7081                 }
7082         }
7083
7084         CHECK_CFG_EXCEPTION;
7085
7086         if (header->code_size == 0)
7087                 UNVERIFIED;
7088
7089         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7090                 ip = err_pos;
7091                 UNVERIFIED;
7092         }
7093
7094         if (cfg->method == method)
7095                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7096
7097         for (n = 0; n < header->num_locals; ++n) {
7098                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7099                         UNVERIFIED;
7100         }
7101         class_inits = NULL;
7102
7103         /* We force the vtable variable here for all shared methods
7104            for the possibility that they might show up in a stack
7105            trace where their exact instantiation is needed. */
7106         if (cfg->generic_sharing_context && method == cfg->method) {
7107                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7108                                 mini_method_get_context (method)->method_inst ||
7109                                 method->klass->valuetype) {
7110                         mono_get_vtable_var (cfg);
7111                 } else {
7112                         /* FIXME: Is there a better way to do this?
7113                            We need the variable live for the duration
7114                            of the whole method. */
7115                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7116                 }
7117         }
7118
7119         /* add a check for this != NULL to inlined methods */
7120         if (is_virtual_call) {
7121                 MonoInst *arg_ins;
7122
7123                 NEW_ARGLOAD (cfg, arg_ins, 0);
7124                 MONO_ADD_INS (cfg->cbb, arg_ins);
7125                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7126         }
7127
7128         skip_dead_blocks = !dont_verify;
7129         if (skip_dead_blocks) {
7130                 original_bb = bb = mono_basic_block_split (method, &error);
7131                 if (!mono_error_ok (&error)) {
7132                         mono_error_cleanup (&error);
7133                         UNVERIFIED;
7134                 }
7135                 g_assert (bb);
7136         }
7137
7138         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7139         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7140
7141         ins_flag = 0;
7142         start_new_bblock = 0;
7143         cfg->cbb = bblock;
7144         while (ip < end) {
7145                 if (cfg->method == method)
7146                         cfg->real_offset = ip - header->code;
7147                 else
7148                         cfg->real_offset = inline_offset;
7149                 cfg->ip = ip;
7150
7151                 context_used = 0;
7152                 
7153                 if (start_new_bblock) {
7154                         bblock->cil_length = ip - bblock->cil_code;
7155                         if (start_new_bblock == 2) {
7156                                 g_assert (ip == tblock->cil_code);
7157                         } else {
7158                                 GET_BBLOCK (cfg, tblock, ip);
7159                         }
7160                         bblock->next_bb = tblock;
7161                         bblock = tblock;
7162                         cfg->cbb = bblock;
7163                         start_new_bblock = 0;
7164                         for (i = 0; i < bblock->in_scount; ++i) {
7165                                 if (cfg->verbose_level > 3)
7166                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7167                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7168                                 *sp++ = ins;
7169                         }
7170                         if (class_inits)
7171                                 g_slist_free (class_inits);
7172                         class_inits = NULL;
7173                 } else {
7174                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7175                                 link_bblock (cfg, bblock, tblock);
7176                                 if (sp != stack_start) {
7177                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7178                                         sp = stack_start;
7179                                         CHECK_UNVERIFIABLE (cfg);
7180                                 }
7181                                 bblock->next_bb = tblock;
7182                                 bblock = tblock;
7183                                 cfg->cbb = bblock;
7184                                 for (i = 0; i < bblock->in_scount; ++i) {
7185                                         if (cfg->verbose_level > 3)
7186                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7187                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7188                                         *sp++ = ins;
7189                                 }
7190                                 g_slist_free (class_inits);
7191                                 class_inits = NULL;
7192                         }
7193                 }
7194
7195                 if (skip_dead_blocks) {
7196                         int ip_offset = ip - header->code;
7197
7198                         if (ip_offset == bb->end)
7199                                 bb = bb->next;
7200
7201                         if (bb->dead) {
7202                                 int op_size = mono_opcode_size (ip, end);
7203                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7204
7205                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7206
7207                                 if (ip_offset + op_size == bb->end) {
7208                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7209                                         MONO_ADD_INS (bblock, ins);
7210                                         start_new_bblock = 1;
7211                                 }
7212
7213                                 ip += op_size;
7214                                 continue;
7215                         }
7216                 }
7217                 /*
7218                  * Sequence points are points where the debugger can place a breakpoint.
7219                  * Currently, we generate these automatically at points where the IL
7220                  * stack is empty.
7221                  */
7222                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7223                         /*
7224                          * Make methods interruptable at the beginning, and at the targets of
7225                          * backward branches.
7226                          * Also, do this at the start of every bblock in methods with clauses too,
7227                          * to be able to handle instructions with inprecise control flow like
7228                          * throw/endfinally.
7229                          * Backward branches are handled at the end of method-to-ir ().
7230                          */
7231                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7232
7233                         /* Avoid sequence points on empty IL like .volatile */
7234                         // FIXME: Enable this
7235                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7236                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7237                         if (sp != stack_start)
7238                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7239                         MONO_ADD_INS (cfg->cbb, ins);
7240
7241                         if (sym_seq_points)
7242                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7243                 }
7244
7245                 bblock->real_offset = cfg->real_offset;
7246
7247                 if ((cfg->method == method) && cfg->coverage_info) {
7248                         guint32 cil_offset = ip - header->code;
7249                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7250
7251                         /* TODO: Use an increment here */
7252 #if defined(TARGET_X86)
7253                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7254                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7255                         ins->inst_imm = 1;
7256                         MONO_ADD_INS (cfg->cbb, ins);
7257 #else
7258                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7259                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7260 #endif
7261                 }
7262
7263                 if (cfg->verbose_level > 3)
7264                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7265
7266                 switch (*ip) {
7267                 case CEE_NOP:
7268                         if (seq_points && !sym_seq_points && sp != stack_start) {
7269                                 /*
7270                                  * The C# compiler uses these nops to notify the JIT that it should
7271                                  * insert seq points.
7272                                  */
7273                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7274                                 MONO_ADD_INS (cfg->cbb, ins);
7275                         }
7276                         if (cfg->keep_cil_nops)
7277                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7278                         else
7279                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7280                         ip++;
7281                         MONO_ADD_INS (bblock, ins);
7282                         break;
7283                 case CEE_BREAK:
7284                         if (should_insert_brekpoint (cfg->method)) {
7285                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7286                         } else {
7287                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7288                         }
7289                         ip++;
7290                         MONO_ADD_INS (bblock, ins);
7291                         break;
7292                 case CEE_LDARG_0:
7293                 case CEE_LDARG_1:
7294                 case CEE_LDARG_2:
7295                 case CEE_LDARG_3:
7296                         CHECK_STACK_OVF (1);
7297                         n = (*ip)-CEE_LDARG_0;
7298                         CHECK_ARG (n);
7299                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7300                         ip++;
7301                         *sp++ = ins;
7302                         break;
7303                 case CEE_LDLOC_0:
7304                 case CEE_LDLOC_1:
7305                 case CEE_LDLOC_2:
7306                 case CEE_LDLOC_3:
7307                         CHECK_STACK_OVF (1);
7308                         n = (*ip)-CEE_LDLOC_0;
7309                         CHECK_LOCAL (n);
7310                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7311                         ip++;
7312                         *sp++ = ins;
7313                         break;
7314                 case CEE_STLOC_0:
7315                 case CEE_STLOC_1:
7316                 case CEE_STLOC_2:
7317                 case CEE_STLOC_3: {
7318                         CHECK_STACK (1);
7319                         n = (*ip)-CEE_STLOC_0;
7320                         CHECK_LOCAL (n);
7321                         --sp;
7322                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7323                                 UNVERIFIED;
7324                         emit_stloc_ir (cfg, sp, header, n);
7325                         ++ip;
7326                         inline_costs += 1;
7327                         break;
7328                         }
7329                 case CEE_LDARG_S:
7330                         CHECK_OPSIZE (2);
7331                         CHECK_STACK_OVF (1);
7332                         n = ip [1];
7333                         CHECK_ARG (n);
7334                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7335                         *sp++ = ins;
7336                         ip += 2;
7337                         break;
7338                 case CEE_LDARGA_S:
7339                         CHECK_OPSIZE (2);
7340                         CHECK_STACK_OVF (1);
7341                         n = ip [1];
7342                         CHECK_ARG (n);
7343                         NEW_ARGLOADA (cfg, ins, n);
7344                         MONO_ADD_INS (cfg->cbb, ins);
7345                         *sp++ = ins;
7346                         ip += 2;
7347                         break;
7348                 case CEE_STARG_S:
7349                         CHECK_OPSIZE (2);
7350                         CHECK_STACK (1);
7351                         --sp;
7352                         n = ip [1];
7353                         CHECK_ARG (n);
7354                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7355                                 UNVERIFIED;
7356                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7357                         ip += 2;
7358                         break;
7359                 case CEE_LDLOC_S:
7360                         CHECK_OPSIZE (2);
7361                         CHECK_STACK_OVF (1);
7362                         n = ip [1];
7363                         CHECK_LOCAL (n);
7364                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7365                         *sp++ = ins;
7366                         ip += 2;
7367                         break;
7368                 case CEE_LDLOCA_S: {
7369                         unsigned char *tmp_ip;
7370                         CHECK_OPSIZE (2);
7371                         CHECK_STACK_OVF (1);
7372                         CHECK_LOCAL (ip [1]);
7373
7374                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7375                                 ip = tmp_ip;
7376                                 inline_costs += 1;
7377                                 break;
7378                         }
7379
7380                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7381                         *sp++ = ins;
7382                         ip += 2;
7383                         break;
7384                 }
7385                 case CEE_STLOC_S:
7386                         CHECK_OPSIZE (2);
7387                         CHECK_STACK (1);
7388                         --sp;
7389                         CHECK_LOCAL (ip [1]);
7390                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7391                                 UNVERIFIED;
7392                         emit_stloc_ir (cfg, sp, header, ip [1]);
7393                         ip += 2;
7394                         inline_costs += 1;
7395                         break;
7396                 case CEE_LDNULL:
7397                         CHECK_STACK_OVF (1);
7398                         EMIT_NEW_PCONST (cfg, ins, NULL);
7399                         ins->type = STACK_OBJ;
7400                         ++ip;
7401                         *sp++ = ins;
7402                         break;
7403                 case CEE_LDC_I4_M1:
7404                         CHECK_STACK_OVF (1);
7405                         EMIT_NEW_ICONST (cfg, ins, -1);
7406                         ++ip;
7407                         *sp++ = ins;
7408                         break;
7409                 case CEE_LDC_I4_0:
7410                 case CEE_LDC_I4_1:
7411                 case CEE_LDC_I4_2:
7412                 case CEE_LDC_I4_3:
7413                 case CEE_LDC_I4_4:
7414                 case CEE_LDC_I4_5:
7415                 case CEE_LDC_I4_6:
7416                 case CEE_LDC_I4_7:
7417                 case CEE_LDC_I4_8:
7418                         CHECK_STACK_OVF (1);
7419                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7420                         ++ip;
7421                         *sp++ = ins;
7422                         break;
7423                 case CEE_LDC_I4_S:
7424                         CHECK_OPSIZE (2);
7425                         CHECK_STACK_OVF (1);
7426                         ++ip;
7427                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7428                         ++ip;
7429                         *sp++ = ins;
7430                         break;
7431                 case CEE_LDC_I4:
7432                         CHECK_OPSIZE (5);
7433                         CHECK_STACK_OVF (1);
7434                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7435                         ip += 5;
7436                         *sp++ = ins;
7437                         break;
7438                 case CEE_LDC_I8:
7439                         CHECK_OPSIZE (9);
7440                         CHECK_STACK_OVF (1);
7441                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7442                         ins->type = STACK_I8;
7443                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7444                         ++ip;
7445                         ins->inst_l = (gint64)read64 (ip);
7446                         MONO_ADD_INS (bblock, ins);
7447                         ip += 8;
7448                         *sp++ = ins;
7449                         break;
7450                 case CEE_LDC_R4: {
7451                         float *f;
7452                         gboolean use_aotconst = FALSE;
7453
7454 #ifdef TARGET_POWERPC
7455                         /* FIXME: Clean this up */
7456                         if (cfg->compile_aot)
7457                                 use_aotconst = TRUE;
7458 #endif
7459
7460                         /* FIXME: we should really allocate this only late in the compilation process */
7461                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7462                         CHECK_OPSIZE (5);
7463                         CHECK_STACK_OVF (1);
7464
7465                         if (use_aotconst) {
7466                                 MonoInst *cons;
7467                                 int dreg;
7468
7469                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7470
7471                                 dreg = alloc_freg (cfg);
7472                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7473                                 ins->type = STACK_R8;
7474                         } else {
7475                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7476                                 ins->type = STACK_R8;
7477                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7478                                 ins->inst_p0 = f;
7479                                 MONO_ADD_INS (bblock, ins);
7480                         }
7481                         ++ip;
7482                         readr4 (ip, f);
7483                         ip += 4;
7484                         *sp++ = ins;                    
7485                         break;
7486                 }
7487                 case CEE_LDC_R8: {
7488                         double *d;
7489                         gboolean use_aotconst = FALSE;
7490
7491 #ifdef TARGET_POWERPC
7492                         /* FIXME: Clean this up */
7493                         if (cfg->compile_aot)
7494                                 use_aotconst = TRUE;
7495 #endif
7496
7497                         /* FIXME: we should really allocate this only late in the compilation process */
7498                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7499                         CHECK_OPSIZE (9);
7500                         CHECK_STACK_OVF (1);
7501
7502                         if (use_aotconst) {
7503                                 MonoInst *cons;
7504                                 int dreg;
7505
7506                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7507
7508                                 dreg = alloc_freg (cfg);
7509                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7510                                 ins->type = STACK_R8;
7511                         } else {
7512                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7513                                 ins->type = STACK_R8;
7514                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7515                                 ins->inst_p0 = d;
7516                                 MONO_ADD_INS (bblock, ins);
7517                         }
7518                         ++ip;
7519                         readr8 (ip, d);
7520                         ip += 8;
7521                         *sp++ = ins;
7522                         break;
7523                 }
7524                 case CEE_DUP: {
7525                         MonoInst *temp, *store;
7526                         CHECK_STACK (1);
7527                         CHECK_STACK_OVF (1);
7528                         sp--;
7529                         ins = *sp;
7530
7531                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7532                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7533
7534                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7535                         *sp++ = ins;
7536
7537                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7538                         *sp++ = ins;
7539
7540                         ++ip;
7541                         inline_costs += 2;
7542                         break;
7543                 }
7544                 case CEE_POP:
7545                         CHECK_STACK (1);
7546                         ip++;
7547                         --sp;
7548
7549 #ifdef TARGET_X86
7550                         if (sp [0]->type == STACK_R8)
7551                                 /* we need to pop the value from the x86 FP stack */
7552                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7553 #endif
7554                         break;
7555                 case CEE_JMP: {
7556                         MonoCallInst *call;
7557
7558                         INLINE_FAILURE ("jmp");
7559                         GSHAREDVT_FAILURE (*ip);
7560
7561                         CHECK_OPSIZE (5);
7562                         if (stack_start != sp)
7563                                 UNVERIFIED;
7564                         token = read32 (ip + 1);
7565                         /* FIXME: check the signature matches */
7566                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7567
7568                         if (!cmethod || mono_loader_get_last_error ())
7569                                 LOAD_ERROR;
7570  
7571                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7572                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7573
7574                         if (mono_security_cas_enabled ())
7575                                 CHECK_CFG_EXCEPTION;
7576
7577                         if (ARCH_HAVE_OP_TAIL_CALL) {
7578                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7579                                 int i, n;
7580
7581                                 /* Handle tail calls similarly to calls */
7582                                 n = fsig->param_count + fsig->hasthis;
7583
7584                                 DISABLE_AOT (cfg);
7585
7586                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7587                                 call->method = cmethod;
7588                                 call->tail_call = TRUE;
7589                                 call->signature = mono_method_signature (cmethod);
7590                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7591                                 call->inst.inst_p0 = cmethod;
7592                                 for (i = 0; i < n; ++i)
7593                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7594
7595                                 mono_arch_emit_call (cfg, call);
7596                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7597                         } else {
7598                                 for (i = 0; i < num_args; ++i)
7599                                         /* Prevent arguments from being optimized away */
7600                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7601
7602                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7603                                 ins = (MonoInst*)call;
7604                                 ins->inst_p0 = cmethod;
7605                                 MONO_ADD_INS (bblock, ins);
7606                         }
7607
7608                         ip += 5;
7609                         start_new_bblock = 1;
7610                         break;
7611                 }
7612                 case CEE_CALLI:
7613                 case CEE_CALL:
7614                 case CEE_CALLVIRT: {
7615                         MonoInst *addr = NULL;
7616                         MonoMethodSignature *fsig = NULL;
7617                         int array_rank = 0;
7618                         int virtual = *ip == CEE_CALLVIRT;
7619                         int calli = *ip == CEE_CALLI;
7620                         gboolean pass_imt_from_rgctx = FALSE;
7621                         MonoInst *imt_arg = NULL;
7622                         MonoInst *keep_this_alive = NULL;
7623                         gboolean pass_vtable = FALSE;
7624                         gboolean pass_mrgctx = FALSE;
7625                         MonoInst *vtable_arg = NULL;
7626                         gboolean check_this = FALSE;
7627                         gboolean supported_tail_call = FALSE;
7628                         gboolean tail_call = FALSE;
7629                         gboolean need_seq_point = FALSE;
7630                         guint32 call_opcode = *ip;
7631                         gboolean emit_widen = TRUE;
7632                         gboolean push_res = TRUE;
7633                         gboolean skip_ret = FALSE;
7634                         gboolean delegate_invoke = FALSE;
7635
7636                         CHECK_OPSIZE (5);
7637                         token = read32 (ip + 1);
7638
7639                         ins = NULL;
7640
7641                         if (calli) {
7642                                 //GSHAREDVT_FAILURE (*ip);
7643                                 cmethod = NULL;
7644                                 CHECK_STACK (1);
7645                                 --sp;
7646                                 addr = *sp;
7647                                 fsig = mini_get_signature (method, token, generic_context);
7648                                 n = fsig->param_count + fsig->hasthis;
7649
7650                                 if (method->dynamic && fsig->pinvoke) {
7651                                         MonoInst *args [3];
7652
7653                                         /*
7654                                          * This is a call through a function pointer using a pinvoke
7655                                          * signature. Have to create a wrapper and call that instead.
7656                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7657                                          * instead based on the signature.
7658                                          */
7659                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7660                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7661                                         args [2] = addr;
7662                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7663                                 }
7664                         } else {
7665                                 MonoMethod *cil_method;
7666
7667                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7668                                 cil_method = cmethod;
7669                                 
7670                                 if (constrained_call) {
7671                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7672                                                 if (cfg->verbose_level > 2)
7673                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7674                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7675                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7676                                                           cfg->generic_sharing_context)) {
7677                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7678                                                 }
7679                                         } else {
7680                                                 if (cfg->verbose_level > 2)
7681                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7682
7683                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7684                                                         /* 
7685                                                          * This is needed since get_method_constrained can't find 
7686                                                          * the method in klass representing a type var.
7687                                                          * The type var is guaranteed to be a reference type in this
7688                                                          * case.
7689                                                          */
7690                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7691                                                                 g_assert (!cmethod->klass->valuetype);
7692                                                 } else {
7693                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7694                                                 }
7695                                         }
7696                                 }
7697                                         
7698                                 if (!cmethod || mono_loader_get_last_error ())
7699                                         LOAD_ERROR;
7700                                 if (!dont_verify && !cfg->skip_visibility) {
7701                                         MonoMethod *target_method = cil_method;
7702                                         if (method->is_inflated) {
7703                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7704                                         }
7705                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7706                                                 !mono_method_can_access_method (method, cil_method))
7707                                                 METHOD_ACCESS_FAILURE;
7708                                 }
7709
7710                                 if (mono_security_core_clr_enabled ())
7711                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7712
7713                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7714                                         /* MS.NET seems to silently convert this to a callvirt */
7715                                         virtual = 1;
7716
7717                                 {
7718                                         /*
7719                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7720                                          * converts to a callvirt.
7721                                          *
7722                                          * tests/bug-515884.il is an example of this behavior
7723                                          */
7724                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7725                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7726                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7727                                                 virtual = 1;
7728                                 }
7729
7730                                 if (!cmethod->klass->inited)
7731                                         if (!mono_class_init (cmethod->klass))
7732                                                 TYPE_LOAD_ERROR (cmethod->klass);
7733
7734                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7735                                     mini_class_is_system_array (cmethod->klass)) {
7736                                         array_rank = cmethod->klass->rank;
7737                                         fsig = mono_method_signature (cmethod);
7738                                 } else {
7739                                         fsig = mono_method_signature (cmethod);
7740
7741                                         if (!fsig)
7742                                                 LOAD_ERROR;
7743
7744                                         if (fsig->pinvoke) {
7745                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7746                                                         check_for_pending_exc, cfg->compile_aot);
7747                                                 fsig = mono_method_signature (wrapper);
7748                                         } else if (constrained_call) {
7749                                                 fsig = mono_method_signature (cmethod);
7750                                         } else {
7751                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7752                                         }
7753                                 }
7754
7755                                 mono_save_token_info (cfg, image, token, cil_method);
7756
7757                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7758                                         /*
7759                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7760                                          * foo (bar (), baz ())
7761                                          * works correctly. MS does this also:
7762                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7763                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7764                                          * even for simple cases, like:
7765                                          * int i = foo ();
7766                                          */
7767                                         /* Special case a few common successor opcodes */
7768                                         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)))
7769                                                 need_seq_point = TRUE;
7770                                 }
7771
7772                                 n = fsig->param_count + fsig->hasthis;
7773
7774                                 /* Don't support calls made using type arguments for now */
7775                                 /*
7776                                 if (cfg->gsharedvt) {
7777                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7778                                                 GSHAREDVT_FAILURE (*ip);
7779                                 }
7780                                 */
7781
7782                                 if (mono_security_cas_enabled ()) {
7783                                         if (check_linkdemand (cfg, method, cmethod))
7784                                                 INLINE_FAILURE ("linkdemand");
7785                                         CHECK_CFG_EXCEPTION;
7786                                 }
7787
7788                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7789                                         g_assert_not_reached ();
7790                         }
7791
7792                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7793                                 UNVERIFIED;
7794
7795                         if (!cfg->generic_sharing_context && cmethod)
7796                                 g_assert (!mono_method_check_context_used (cmethod));
7797
7798                         CHECK_STACK (n);
7799
7800                         //g_assert (!virtual || fsig->hasthis);
7801
7802                         sp -= n;
7803
7804                         if (constrained_call) {
7805                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7806                                         /*
7807                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7808                                          */
7809                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7810                                                 /* The 'Own method' case below */
7811                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7812                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7813                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7814                                                            (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)) &&
7815                                                            (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]))))) {
7816                                                 MonoInst *args [16];
7817
7818                                                 /*
7819                                                  * This case handles calls to
7820                                                  * - object:ToString()/Equals()/GetHashCode(),
7821                                                  * - System.IComparable<T>:CompareTo()
7822                                                  * - System.IEquatable<T>:Equals ()
7823                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7824                                                  */
7825
7826                                                 args [0] = sp [0];
7827                                                 if (mono_method_check_context_used (cmethod))
7828                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7829                                                 else
7830                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7831                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7832
7833                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7834                                                 if (fsig->hasthis && fsig->param_count) {
7835                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7836                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7837                                                         ins->dreg = alloc_preg (cfg);
7838                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7839                                                         MONO_ADD_INS (cfg->cbb, ins);
7840                                                         args [4] = ins;
7841
7842                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7843                                                                 int addr_reg;
7844
7845                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
7846
7847                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
7848                                                                 addr_reg = ins->dreg;
7849                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
7850                                                         } else {
7851                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
7852                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
7853                                                         }
7854                                                 } else {
7855                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
7856                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
7857                                                 }
7858                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
7859                                                 emit_widen = FALSE;
7860
7861                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
7862                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
7863                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
7864                                                         MonoInst *add;
7865
7866                                                         /* Unbox */
7867                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
7868                                                         MONO_ADD_INS (cfg->cbb, add);
7869                                                         /* Load value */
7870                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
7871                                                         MONO_ADD_INS (cfg->cbb, ins);
7872                                                         /* ins represents the call result */
7873                                                 }
7874
7875                                                 goto call_end;
7876                                         } else {
7877                                                 GSHAREDVT_FAILURE (*ip);
7878                                         }
7879                                 }
7880                                 /*
7881                                  * We have the `constrained.' prefix opcode.
7882                                  */
7883                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
7884                                         /*
7885                                          * The type parameter is instantiated as a valuetype,
7886                                          * but that type doesn't override the method we're
7887                                          * calling, so we need to box `this'.
7888                                          */
7889                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7890                                         ins->klass = constrained_call;
7891                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7892                                         CHECK_CFG_EXCEPTION;
7893                                 } else if (!constrained_call->valuetype) {
7894                                         int dreg = alloc_ireg_ref (cfg);
7895
7896                                         /*
7897                                          * The type parameter is instantiated as a reference
7898                                          * type.  We have a managed pointer on the stack, so
7899                                          * we need to dereference it here.
7900                                          */
7901                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
7902                                         ins->type = STACK_OBJ;
7903                                         sp [0] = ins;
7904                                 } else {
7905                                         if (cmethod->klass->valuetype) {
7906                                                 /* Own method */
7907                                         } else {
7908                                                 /* Interface method */
7909                                                 int ioffset, slot;
7910
7911                                                 mono_class_setup_vtable (constrained_call);
7912                                                 CHECK_TYPELOAD (constrained_call);
7913                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
7914                                                 if (ioffset == -1)
7915                                                         TYPE_LOAD_ERROR (constrained_call);
7916                                                 slot = mono_method_get_vtable_slot (cmethod);
7917                                                 if (slot == -1)
7918                                                         TYPE_LOAD_ERROR (cmethod->klass);
7919                                                 cmethod = constrained_call->vtable [ioffset + slot];
7920
7921                                                 if (cmethod->klass == mono_defaults.enum_class) {
7922                                                         /* Enum implements some interfaces, so treat this as the first case */
7923                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7924                                                         ins->klass = constrained_call;
7925                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7926                                                         CHECK_CFG_EXCEPTION;
7927                                                 }
7928                                         }
7929                                         virtual = 0;
7930                                 }
7931                                 constrained_call = NULL;
7932                         }
7933
7934                         if (!calli && check_call_signature (cfg, fsig, sp))
7935                                 UNVERIFIED;
7936
7937 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7938                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
7939                                 delegate_invoke = TRUE;
7940 #endif
7941
7942                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
7943                                 bblock = cfg->cbb;
7944                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7945                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7946                                         emit_widen = FALSE;
7947                                 }
7948
7949                                 goto call_end;
7950                         }
7951
7952                         /* 
7953                          * If the callee is a shared method, then its static cctor
7954                          * might not get called after the call was patched.
7955                          */
7956                         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)) {
7957                                 emit_generic_class_init (cfg, cmethod->klass);
7958                                 CHECK_TYPELOAD (cmethod->klass);
7959                         }
7960
7961                         if (cmethod)
7962                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
7963
7964                         if (cfg->generic_sharing_context && cmethod) {
7965                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
7966
7967                                 context_used = mini_method_check_context_used (cfg, cmethod);
7968
7969                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7970                                         /* Generic method interface
7971                                            calls are resolved via a
7972                                            helper function and don't
7973                                            need an imt. */
7974                                         if (!cmethod_context || !cmethod_context->method_inst)
7975                                                 pass_imt_from_rgctx = TRUE;
7976                                 }
7977
7978                                 /*
7979                                  * If a shared method calls another
7980                                  * shared method then the caller must
7981                                  * have a generic sharing context
7982                                  * because the magic trampoline
7983                                  * requires it.  FIXME: We shouldn't
7984                                  * have to force the vtable/mrgctx
7985                                  * variable here.  Instead there
7986                                  * should be a flag in the cfg to
7987                                  * request a generic sharing context.
7988                                  */
7989                                 if (context_used &&
7990                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
7991                                         mono_get_vtable_var (cfg);
7992                         }
7993
7994                         if (pass_vtable) {
7995                                 if (context_used) {
7996                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7997                                 } else {
7998                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7999
8000                                         CHECK_TYPELOAD (cmethod->klass);
8001                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8002                                 }
8003                         }
8004
8005                         if (pass_mrgctx) {
8006                                 g_assert (!vtable_arg);
8007
8008                                 if (!cfg->compile_aot) {
8009                                         /* 
8010                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8011                                          * for type load errors before.
8012                                          */
8013                                         mono_class_setup_vtable (cmethod->klass);
8014                                         CHECK_TYPELOAD (cmethod->klass);
8015                                 }
8016
8017                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8018
8019                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8020                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8021                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8022                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8023                                         if (virtual)
8024                                                 check_this = TRUE;
8025                                         virtual = 0;
8026                                 }
8027                         }
8028
8029                         if (pass_imt_from_rgctx) {
8030                                 g_assert (!pass_vtable);
8031                                 g_assert (cmethod);
8032
8033                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8034                                         cmethod, MONO_RGCTX_INFO_METHOD);
8035                         }
8036
8037                         if (check_this)
8038                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8039
8040                         /* Calling virtual generic methods */
8041                         if (cmethod && virtual && 
8042                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8043                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8044                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8045                             fsig->generic_param_count && 
8046                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8047                                 MonoInst *this_temp, *this_arg_temp, *store;
8048                                 MonoInst *iargs [4];
8049                                 gboolean use_imt = FALSE;
8050
8051                                 g_assert (fsig->is_inflated);
8052
8053                                 /* Prevent inlining of methods that contain indirect calls */
8054                                 INLINE_FAILURE ("virtual generic call");
8055
8056                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8057                                         GSHAREDVT_FAILURE (*ip);
8058
8059 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8060                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8061                                         use_imt = TRUE;
8062 #endif
8063
8064                                 if (use_imt) {
8065                                         g_assert (!imt_arg);
8066                                         if (!context_used)
8067                                                 g_assert (cmethod->is_inflated);
8068                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8069                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8070                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8071                                 } else {
8072                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8073                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8074                                         MONO_ADD_INS (bblock, store);
8075
8076                                         /* FIXME: This should be a managed pointer */
8077                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8078
8079                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8080                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8081                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8082                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8083                                         addr = mono_emit_jit_icall (cfg,
8084                                                                                                 mono_helper_compile_generic_method, iargs);
8085
8086                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8087
8088                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8089                                 }
8090
8091                                 goto call_end;
8092                         }
8093
8094                         /*
8095                          * Implement a workaround for the inherent races involved in locking:
8096                          * Monitor.Enter ()
8097                          * try {
8098                          * } finally {
8099                          *    Monitor.Exit ()
8100                          * }
8101                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8102                          * try block, the Exit () won't be executed, see:
8103                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8104                          * To work around this, we extend such try blocks to include the last x bytes
8105                          * of the Monitor.Enter () call.
8106                          */
8107                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8108                                 MonoBasicBlock *tbb;
8109
8110                                 GET_BBLOCK (cfg, tbb, ip + 5);
8111                                 /* 
8112                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8113                                  * from Monitor.Enter like ArgumentNullException.
8114                                  */
8115                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8116                                         /* Mark this bblock as needing to be extended */
8117                                         tbb->extend_try_block = TRUE;
8118                                 }
8119                         }
8120
8121                         /* Conversion to a JIT intrinsic */
8122                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8123                                 bblock = cfg->cbb;
8124                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8125                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8126                                         emit_widen = FALSE;
8127                                 }
8128                                 goto call_end;
8129                         }
8130
8131                         /* Inlining */
8132                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8133                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8134                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8135                                  !g_list_find (dont_inline, cmethod)) {
8136                                 int costs;
8137                                 gboolean always = FALSE;
8138
8139                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8140                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8141                                         /* Prevent inlining of methods that call wrappers */
8142                                         INLINE_FAILURE ("wrapper call");
8143                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8144                                         always = TRUE;
8145                                 }
8146
8147                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8148                                 if (costs) {
8149                                         cfg->real_offset += 5;
8150                                         bblock = cfg->cbb;
8151
8152                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8153                                                 /* *sp is already set by inline_method */
8154                                                 sp++;
8155                                                 push_res = FALSE;
8156                                         }
8157
8158                                         inline_costs += costs;
8159
8160                                         goto call_end;
8161                                 }
8162                         }
8163
8164                         /* Tail recursion elimination */
8165                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8166                                 gboolean has_vtargs = FALSE;
8167                                 int i;
8168
8169                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8170                                 INLINE_FAILURE ("tail call");
8171
8172                                 /* keep it simple */
8173                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8174                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8175                                                 has_vtargs = TRUE;
8176                                 }
8177
8178                                 if (!has_vtargs) {
8179                                         for (i = 0; i < n; ++i)
8180                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8181                                         MONO_INST_NEW (cfg, ins, OP_BR);
8182                                         MONO_ADD_INS (bblock, ins);
8183                                         tblock = start_bblock->out_bb [0];
8184                                         link_bblock (cfg, bblock, tblock);
8185                                         ins->inst_target_bb = tblock;
8186                                         start_new_bblock = 1;
8187
8188                                         /* skip the CEE_RET, too */
8189                                         if (ip_in_bb (cfg, bblock, ip + 5))
8190                                                 skip_ret = TRUE;
8191                                         push_res = FALSE;
8192                                         goto call_end;
8193                                 }
8194                         }
8195
8196                         inline_costs += 10 * num_calls++;
8197
8198                         /*
8199                          * Making generic calls out of gsharedvt methods.
8200                          */
8201                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8202                                 MonoRgctxInfoType info_type;
8203
8204                                 if (virtual) {
8205                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8206                                                 //GSHAREDVT_FAILURE (*ip);
8207                                         // disable for possible remoting calls
8208                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8209                                                 GSHAREDVT_FAILURE (*ip);
8210                                         if (fsig->generic_param_count) {
8211                                                 /* virtual generic call */
8212                                                 g_assert (mono_use_imt);
8213                                                 g_assert (!imt_arg);
8214                                                 /* Same as the virtual generic case above */
8215                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8216                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8217                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8218                                                 vtable_arg = NULL;
8219                                         }
8220                                 }
8221
8222                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8223                                         /* test_0_multi_dim_arrays () in gshared.cs */
8224                                         GSHAREDVT_FAILURE (*ip);
8225
8226                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8227                                         keep_this_alive = sp [0];
8228
8229                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8230                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8231                                 else
8232                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8233                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8234
8235                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8236                                 goto call_end;
8237                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8238                                 /*
8239                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8240                                  */
8241                                 MonoInst *callee = addr;
8242
8243                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8244                                         /* Not tested */
8245                                         GSHAREDVT_FAILURE (*ip);
8246
8247                                 addr = emit_get_rgctx_sig (cfg, context_used,
8248                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8249                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8250                                 goto call_end;
8251                         }
8252
8253                         /* Generic sharing */
8254                         /* FIXME: only do this for generic methods if
8255                            they are not shared! */
8256                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8257                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8258                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8259                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8260                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8261                                 INLINE_FAILURE ("gshared");
8262
8263                                 g_assert (cfg->generic_sharing_context && cmethod);
8264                                 g_assert (!addr);
8265
8266                                 /*
8267                                  * We are compiling a call to a
8268                                  * generic method from shared code,
8269                                  * which means that we have to look up
8270                                  * the method in the rgctx and do an
8271                                  * indirect call.
8272                                  */
8273                                 if (fsig->hasthis)
8274                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8275
8276                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8277                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8278                                 goto call_end;
8279                         }
8280
8281                         /* Indirect calls */
8282                         if (addr) {
8283                                 if (call_opcode == CEE_CALL)
8284                                         g_assert (context_used);
8285                                 else if (call_opcode == CEE_CALLI)
8286                                         g_assert (!vtable_arg);
8287                                 else
8288                                         /* FIXME: what the hell is this??? */
8289                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8290                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8291
8292                                 /* Prevent inlining of methods with indirect calls */
8293                                 INLINE_FAILURE ("indirect call");
8294
8295                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8296                                         int info_type;
8297                                         gpointer info_data;
8298
8299                                         /* 
8300                                          * Instead of emitting an indirect call, emit a direct call
8301                                          * with the contents of the aotconst as the patch info.
8302                                          */
8303                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8304                                                 info_type = addr->inst_c1;
8305                                                 info_data = addr->inst_p0;
8306                                         } else {
8307                                                 info_type = addr->inst_right->inst_c1;
8308                                                 info_data = addr->inst_right->inst_left;
8309                                         }
8310                                         
8311                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8312                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8313                                                 NULLIFY_INS (addr);
8314                                                 goto call_end;
8315                                         }
8316                                 }
8317                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8318                                 goto call_end;
8319                         }
8320                                         
8321                         /* Array methods */
8322                         if (array_rank) {
8323                                 MonoInst *addr;
8324
8325                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8326                                         MonoInst *val = sp [fsig->param_count];
8327
8328                                         if (val->type == STACK_OBJ) {
8329                                                 MonoInst *iargs [2];
8330
8331                                                 iargs [0] = sp [0];
8332                                                 iargs [1] = val;
8333                                                 
8334                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8335                                         }
8336                                         
8337                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8338                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8339                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8340                                                 emit_write_barrier (cfg, addr, val);
8341                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8342                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8343
8344                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8345                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8346                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8347                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8348                                         CHECK_TYPELOAD (cmethod->klass);
8349                                         
8350                                         readonly = FALSE;
8351                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8352                                         ins = addr;
8353                                 } else {
8354                                         g_assert_not_reached ();
8355                                 }
8356
8357                                 emit_widen = FALSE;
8358                                 goto call_end;
8359                         }
8360
8361                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8362                         if (ins)
8363                                 goto call_end;
8364
8365                         /* Tail prefix / tail call optimization */
8366
8367                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8368                         /* FIXME: runtime generic context pointer for jumps? */
8369                         /* FIXME: handle this for generic sharing eventually */
8370                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8371                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8372                                 supported_tail_call = TRUE;
8373
8374                         if (supported_tail_call) {
8375                                 MonoCallInst *call;
8376
8377                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8378                                 INLINE_FAILURE ("tail call");
8379
8380                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8381
8382                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8383                                         /* Handle tail calls similarly to normal calls */
8384                                         tail_call = TRUE;
8385                                 } else {
8386                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8387                                         call->tail_call = TRUE;
8388                                         call->method = cmethod;
8389                                         call->signature = mono_method_signature (cmethod);
8390
8391                                         /*
8392                                          * We implement tail calls by storing the actual arguments into the 
8393                                          * argument variables, then emitting a CEE_JMP.
8394                                          */
8395                                         for (i = 0; i < n; ++i) {
8396                                                 /* Prevent argument from being register allocated */
8397                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8398                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8399                                         }
8400                                         ins = (MonoInst*)call;
8401                                         ins->inst_p0 = cmethod;
8402                                         ins->inst_p1 = arg_array [0];
8403                                         MONO_ADD_INS (bblock, ins);
8404                                         link_bblock (cfg, bblock, end_bblock);                  
8405                                         start_new_bblock = 1;
8406
8407                                         // FIXME: Eliminate unreachable epilogs
8408
8409                                         /*
8410                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8411                                          * only reachable from this call.
8412                                          */
8413                                         GET_BBLOCK (cfg, tblock, ip + 5);
8414                                         if (tblock == bblock || tblock->in_count == 0)
8415                                                 skip_ret = TRUE;
8416                                         push_res = FALSE;
8417
8418                                         goto call_end;
8419                                 }
8420                         }
8421
8422                         /* 
8423                          * Synchronized wrappers.
8424                          * Its hard to determine where to replace a method with its synchronized
8425                          * wrapper without causing an infinite recursion. The current solution is
8426                          * to add the synchronized wrapper in the trampolines, and to
8427                          * change the called method to a dummy wrapper, and resolve that wrapper
8428                          * to the real method in mono_jit_compile_method ().
8429                          */
8430                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8431                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8432                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8433                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8434                         }
8435
8436                         /* Common call */
8437                         INLINE_FAILURE ("call");
8438                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8439                                                                                           imt_arg, vtable_arg);
8440
8441                         if (tail_call) {
8442                                 link_bblock (cfg, bblock, end_bblock);                  
8443                                 start_new_bblock = 1;
8444
8445                                 // FIXME: Eliminate unreachable epilogs
8446
8447                                 /*
8448                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8449                                  * only reachable from this call.
8450                                  */
8451                                 GET_BBLOCK (cfg, tblock, ip + 5);
8452                                 if (tblock == bblock || tblock->in_count == 0)
8453                                         skip_ret = TRUE;
8454                                 push_res = FALSE;
8455                         }
8456
8457                         call_end:
8458
8459                         /* End of call, INS should contain the result of the call, if any */
8460
8461                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8462                                 g_assert (ins);
8463                                 if (emit_widen)
8464                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8465                                 else
8466                                         *sp++ = ins;
8467                         }
8468
8469                         if (keep_this_alive) {
8470                                 MonoInst *dummy_use;
8471
8472                                 /* See mono_emit_method_call_full () */
8473                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8474                         }
8475
8476                         CHECK_CFG_EXCEPTION;
8477
8478                         ip += 5;
8479                         if (skip_ret) {
8480                                 g_assert (*ip == CEE_RET);
8481                                 ip += 1;
8482                         }
8483                         ins_flag = 0;
8484                         constrained_call = NULL;
8485                         if (need_seq_point)
8486                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8487                         break;
8488                 }
8489                 case CEE_RET:
8490                         if (cfg->method != method) {
8491                                 /* return from inlined method */
8492                                 /* 
8493                                  * If in_count == 0, that means the ret is unreachable due to
8494                                  * being preceeded by a throw. In that case, inline_method () will
8495                                  * handle setting the return value 
8496                                  * (test case: test_0_inline_throw ()).
8497                                  */
8498                                 if (return_var && cfg->cbb->in_count) {
8499                                         MonoType *ret_type = mono_method_signature (method)->ret;
8500
8501                                         MonoInst *store;
8502                                         CHECK_STACK (1);
8503                                         --sp;
8504
8505                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8506                                                 UNVERIFIED;
8507
8508                                         //g_assert (returnvar != -1);
8509                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8510                                         cfg->ret_var_set = TRUE;
8511                                 } 
8512                         } else {
8513                                 if (cfg->lmf_var && cfg->cbb->in_count)
8514                                         emit_pop_lmf (cfg);
8515
8516                                 if (cfg->ret) {
8517                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8518
8519                                         if (seq_points && !sym_seq_points) {
8520                                                 /* 
8521                                                  * Place a seq point here too even through the IL stack is not
8522                                                  * empty, so a step over on
8523                                                  * call <FOO>
8524                                                  * ret
8525                                                  * will work correctly.
8526                                                  */
8527                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8528                                                 MONO_ADD_INS (cfg->cbb, ins);
8529                                         }
8530
8531                                         g_assert (!return_var);
8532                                         CHECK_STACK (1);
8533                                         --sp;
8534
8535                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8536                                                 UNVERIFIED;
8537
8538                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8539                                                 MonoInst *ret_addr;
8540
8541                                                 if (!cfg->vret_addr) {
8542                                                         MonoInst *ins;
8543
8544                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8545                                                 } else {
8546                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8547
8548                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8549                                                         ins->klass = mono_class_from_mono_type (ret_type);
8550                                                 }
8551                                         } else {
8552 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8553                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8554                                                         MonoInst *iargs [1];
8555                                                         MonoInst *conv;
8556
8557                                                         iargs [0] = *sp;
8558                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8559                                                         mono_arch_emit_setret (cfg, method, conv);
8560                                                 } else {
8561                                                         mono_arch_emit_setret (cfg, method, *sp);
8562                                                 }
8563 #else
8564                                                 mono_arch_emit_setret (cfg, method, *sp);
8565 #endif
8566                                         }
8567                                 }
8568                         }
8569                         if (sp != stack_start)
8570                                 UNVERIFIED;
8571                         MONO_INST_NEW (cfg, ins, OP_BR);
8572                         ip++;
8573                         ins->inst_target_bb = end_bblock;
8574                         MONO_ADD_INS (bblock, ins);
8575                         link_bblock (cfg, bblock, end_bblock);
8576                         start_new_bblock = 1;
8577                         break;
8578                 case CEE_BR_S:
8579                         CHECK_OPSIZE (2);
8580                         MONO_INST_NEW (cfg, ins, OP_BR);
8581                         ip++;
8582                         target = ip + 1 + (signed char)(*ip);
8583                         ++ip;
8584                         GET_BBLOCK (cfg, tblock, target);
8585                         link_bblock (cfg, bblock, tblock);
8586                         ins->inst_target_bb = tblock;
8587                         if (sp != stack_start) {
8588                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8589                                 sp = stack_start;
8590                                 CHECK_UNVERIFIABLE (cfg);
8591                         }
8592                         MONO_ADD_INS (bblock, ins);
8593                         start_new_bblock = 1;
8594                         inline_costs += BRANCH_COST;
8595                         break;
8596                 case CEE_BEQ_S:
8597                 case CEE_BGE_S:
8598                 case CEE_BGT_S:
8599                 case CEE_BLE_S:
8600                 case CEE_BLT_S:
8601                 case CEE_BNE_UN_S:
8602                 case CEE_BGE_UN_S:
8603                 case CEE_BGT_UN_S:
8604                 case CEE_BLE_UN_S:
8605                 case CEE_BLT_UN_S:
8606                         CHECK_OPSIZE (2);
8607                         CHECK_STACK (2);
8608                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8609                         ip++;
8610                         target = ip + 1 + *(signed char*)ip;
8611                         ip++;
8612
8613                         ADD_BINCOND (NULL);
8614
8615                         sp = stack_start;
8616                         inline_costs += BRANCH_COST;
8617                         break;
8618                 case CEE_BR:
8619                         CHECK_OPSIZE (5);
8620                         MONO_INST_NEW (cfg, ins, OP_BR);
8621                         ip++;
8622
8623                         target = ip + 4 + (gint32)read32(ip);
8624                         ip += 4;
8625                         GET_BBLOCK (cfg, tblock, target);
8626                         link_bblock (cfg, bblock, tblock);
8627                         ins->inst_target_bb = tblock;
8628                         if (sp != stack_start) {
8629                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8630                                 sp = stack_start;
8631                                 CHECK_UNVERIFIABLE (cfg);
8632                         }
8633
8634                         MONO_ADD_INS (bblock, ins);
8635
8636                         start_new_bblock = 1;
8637                         inline_costs += BRANCH_COST;
8638                         break;
8639                 case CEE_BRFALSE_S:
8640                 case CEE_BRTRUE_S:
8641                 case CEE_BRFALSE:
8642                 case CEE_BRTRUE: {
8643                         MonoInst *cmp;
8644                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8645                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8646                         guint32 opsize = is_short ? 1 : 4;
8647
8648                         CHECK_OPSIZE (opsize);
8649                         CHECK_STACK (1);
8650                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8651                                 UNVERIFIED;
8652                         ip ++;
8653                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8654                         ip += opsize;
8655
8656                         sp--;
8657
8658                         GET_BBLOCK (cfg, tblock, target);
8659                         link_bblock (cfg, bblock, tblock);
8660                         GET_BBLOCK (cfg, tblock, ip);
8661                         link_bblock (cfg, bblock, tblock);
8662
8663                         if (sp != stack_start) {
8664                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8665                                 CHECK_UNVERIFIABLE (cfg);
8666                         }
8667
8668                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8669                         cmp->sreg1 = sp [0]->dreg;
8670                         type_from_op (cmp, sp [0], NULL);
8671                         CHECK_TYPE (cmp);
8672
8673 #if SIZEOF_REGISTER == 4
8674                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8675                                 /* Convert it to OP_LCOMPARE */
8676                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8677                                 ins->type = STACK_I8;
8678                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8679                                 ins->inst_l = 0;
8680                                 MONO_ADD_INS (bblock, ins);
8681                                 cmp->opcode = OP_LCOMPARE;
8682                                 cmp->sreg2 = ins->dreg;
8683                         }
8684 #endif
8685                         MONO_ADD_INS (bblock, cmp);
8686
8687                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8688                         type_from_op (ins, sp [0], NULL);
8689                         MONO_ADD_INS (bblock, ins);
8690                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8691                         GET_BBLOCK (cfg, tblock, target);
8692                         ins->inst_true_bb = tblock;
8693                         GET_BBLOCK (cfg, tblock, ip);
8694                         ins->inst_false_bb = tblock;
8695                         start_new_bblock = 2;
8696
8697                         sp = stack_start;
8698                         inline_costs += BRANCH_COST;
8699                         break;
8700                 }
8701                 case CEE_BEQ:
8702                 case CEE_BGE:
8703                 case CEE_BGT:
8704                 case CEE_BLE:
8705                 case CEE_BLT:
8706                 case CEE_BNE_UN:
8707                 case CEE_BGE_UN:
8708                 case CEE_BGT_UN:
8709                 case CEE_BLE_UN:
8710                 case CEE_BLT_UN:
8711                         CHECK_OPSIZE (5);
8712                         CHECK_STACK (2);
8713                         MONO_INST_NEW (cfg, ins, *ip);
8714                         ip++;
8715                         target = ip + 4 + (gint32)read32(ip);
8716                         ip += 4;
8717
8718                         ADD_BINCOND (NULL);
8719
8720                         sp = stack_start;
8721                         inline_costs += BRANCH_COST;
8722                         break;
8723                 case CEE_SWITCH: {
8724                         MonoInst *src1;
8725                         MonoBasicBlock **targets;
8726                         MonoBasicBlock *default_bblock;
8727                         MonoJumpInfoBBTable *table;
8728                         int offset_reg = alloc_preg (cfg);
8729                         int target_reg = alloc_preg (cfg);
8730                         int table_reg = alloc_preg (cfg);
8731                         int sum_reg = alloc_preg (cfg);
8732                         gboolean use_op_switch;
8733
8734                         CHECK_OPSIZE (5);
8735                         CHECK_STACK (1);
8736                         n = read32 (ip + 1);
8737                         --sp;
8738                         src1 = sp [0];
8739                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8740                                 UNVERIFIED;
8741
8742                         ip += 5;
8743                         CHECK_OPSIZE (n * sizeof (guint32));
8744                         target = ip + n * sizeof (guint32);
8745
8746                         GET_BBLOCK (cfg, default_bblock, target);
8747                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8748
8749                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8750                         for (i = 0; i < n; ++i) {
8751                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8752                                 targets [i] = tblock;
8753                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8754                                 ip += 4;
8755                         }
8756
8757                         if (sp != stack_start) {
8758                                 /* 
8759                                  * Link the current bb with the targets as well, so handle_stack_args
8760                                  * will set their in_stack correctly.
8761                                  */
8762                                 link_bblock (cfg, bblock, default_bblock);
8763                                 for (i = 0; i < n; ++i)
8764                                         link_bblock (cfg, bblock, targets [i]);
8765
8766                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8767                                 sp = stack_start;
8768                                 CHECK_UNVERIFIABLE (cfg);
8769                         }
8770
8771                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8772                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8773                         bblock = cfg->cbb;
8774
8775                         for (i = 0; i < n; ++i)
8776                                 link_bblock (cfg, bblock, targets [i]);
8777
8778                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8779                         table->table = targets;
8780                         table->table_size = n;
8781
8782                         use_op_switch = FALSE;
8783 #ifdef TARGET_ARM
8784                         /* ARM implements SWITCH statements differently */
8785                         /* FIXME: Make it use the generic implementation */
8786                         if (!cfg->compile_aot)
8787                                 use_op_switch = TRUE;
8788 #endif
8789
8790                         if (COMPILE_LLVM (cfg))
8791                                 use_op_switch = TRUE;
8792
8793                         cfg->cbb->has_jump_table = 1;
8794
8795                         if (use_op_switch) {
8796                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8797                                 ins->sreg1 = src1->dreg;
8798                                 ins->inst_p0 = table;
8799                                 ins->inst_many_bb = targets;
8800                                 ins->klass = GUINT_TO_POINTER (n);
8801                                 MONO_ADD_INS (cfg->cbb, ins);
8802                         } else {
8803                                 if (sizeof (gpointer) == 8)
8804                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8805                                 else
8806                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8807
8808 #if SIZEOF_REGISTER == 8
8809                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8810                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8811 #endif
8812
8813                                 if (cfg->compile_aot) {
8814                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8815                                 } else {
8816                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8817                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8818                                         ins->inst_p0 = table;
8819                                         ins->dreg = table_reg;
8820                                         MONO_ADD_INS (cfg->cbb, ins);
8821                                 }
8822
8823                                 /* FIXME: Use load_memindex */
8824                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8825                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8826                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8827                         }
8828                         start_new_bblock = 1;
8829                         inline_costs += (BRANCH_COST * 2);
8830                         break;
8831                 }
8832                 case CEE_LDIND_I1:
8833                 case CEE_LDIND_U1:
8834                 case CEE_LDIND_I2:
8835                 case CEE_LDIND_U2:
8836                 case CEE_LDIND_I4:
8837                 case CEE_LDIND_U4:
8838                 case CEE_LDIND_I8:
8839                 case CEE_LDIND_I:
8840                 case CEE_LDIND_R4:
8841                 case CEE_LDIND_R8:
8842                 case CEE_LDIND_REF:
8843                         CHECK_STACK (1);
8844                         --sp;
8845
8846                         switch (*ip) {
8847                         case CEE_LDIND_R4:
8848                         case CEE_LDIND_R8:
8849                                 dreg = alloc_freg (cfg);
8850                                 break;
8851                         case CEE_LDIND_I8:
8852                                 dreg = alloc_lreg (cfg);
8853                                 break;
8854                         case CEE_LDIND_REF:
8855                                 dreg = alloc_ireg_ref (cfg);
8856                                 break;
8857                         default:
8858                                 dreg = alloc_preg (cfg);
8859                         }
8860
8861                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
8862                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
8863                         ins->flags |= ins_flag;
8864                         ins_flag = 0;
8865                         MONO_ADD_INS (bblock, ins);
8866                         *sp++ = ins;
8867                         if (ins->flags & MONO_INST_VOLATILE) {
8868                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
8869                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8870                                 emit_memory_barrier (cfg, FullBarrier);
8871                         }
8872                         ++ip;
8873                         break;
8874                 case CEE_STIND_REF:
8875                 case CEE_STIND_I1:
8876                 case CEE_STIND_I2:
8877                 case CEE_STIND_I4:
8878                 case CEE_STIND_I8:
8879                 case CEE_STIND_R4:
8880                 case CEE_STIND_R8:
8881                 case CEE_STIND_I:
8882                         CHECK_STACK (2);
8883                         sp -= 2;
8884
8885                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
8886                         ins->flags |= ins_flag;
8887                         ins_flag = 0;
8888
8889                         if (ins->flags & MONO_INST_VOLATILE) {
8890                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
8891                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8892                                 emit_memory_barrier (cfg, FullBarrier);
8893                         }
8894
8895                         MONO_ADD_INS (bblock, ins);
8896
8897                         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)))
8898                                 emit_write_barrier (cfg, sp [0], sp [1]);
8899
8900                         inline_costs += 1;
8901                         ++ip;
8902                         break;
8903
8904                 case CEE_MUL:
8905                         CHECK_STACK (2);
8906
8907                         MONO_INST_NEW (cfg, ins, (*ip));
8908                         sp -= 2;
8909                         ins->sreg1 = sp [0]->dreg;
8910                         ins->sreg2 = sp [1]->dreg;
8911                         type_from_op (ins, sp [0], sp [1]);
8912                         CHECK_TYPE (ins);
8913                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8914
8915                         /* Use the immediate opcodes if possible */
8916                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
8917                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8918                                 if (imm_opcode != -1) {
8919                                         ins->opcode = imm_opcode;
8920                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
8921                                         ins->sreg2 = -1;
8922
8923                                         sp [1]->opcode = OP_NOP;
8924                                 }
8925                         }
8926
8927                         MONO_ADD_INS ((cfg)->cbb, (ins));
8928
8929                         *sp++ = mono_decompose_opcode (cfg, ins);
8930                         ip++;
8931                         break;
8932                 case CEE_ADD:
8933                 case CEE_SUB:
8934                 case CEE_DIV:
8935                 case CEE_DIV_UN:
8936                 case CEE_REM:
8937                 case CEE_REM_UN:
8938                 case CEE_AND:
8939                 case CEE_OR:
8940                 case CEE_XOR:
8941                 case CEE_SHL:
8942                 case CEE_SHR:
8943                 case CEE_SHR_UN:
8944                         CHECK_STACK (2);
8945
8946                         MONO_INST_NEW (cfg, ins, (*ip));
8947                         sp -= 2;
8948                         ins->sreg1 = sp [0]->dreg;
8949                         ins->sreg2 = sp [1]->dreg;
8950                         type_from_op (ins, sp [0], sp [1]);
8951                         CHECK_TYPE (ins);
8952                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
8953                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8954
8955                         /* FIXME: Pass opcode to is_inst_imm */
8956
8957                         /* Use the immediate opcodes if possible */
8958                         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)) {
8959                                 int imm_opcode;
8960
8961                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8962 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
8963                                 /* Keep emulated opcodes which are optimized away later */
8964                                 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) {
8965                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
8966                                 }
8967 #endif
8968                                 if (imm_opcode != -1) {
8969                                         ins->opcode = imm_opcode;
8970                                         if (sp [1]->opcode == OP_I8CONST) {
8971 #if SIZEOF_REGISTER == 8
8972                                                 ins->inst_imm = sp [1]->inst_l;
8973 #else
8974                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
8975                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
8976 #endif
8977                                         }
8978                                         else
8979                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
8980                                         ins->sreg2 = -1;
8981
8982                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
8983                                         if (sp [1]->next == NULL)
8984                                                 sp [1]->opcode = OP_NOP;
8985                                 }
8986                         }
8987                         MONO_ADD_INS ((cfg)->cbb, (ins));
8988
8989                         *sp++ = mono_decompose_opcode (cfg, ins);
8990                         ip++;
8991                         break;
8992                 case CEE_NEG:
8993                 case CEE_NOT:
8994                 case CEE_CONV_I1:
8995                 case CEE_CONV_I2:
8996                 case CEE_CONV_I4:
8997                 case CEE_CONV_R4:
8998                 case CEE_CONV_R8:
8999                 case CEE_CONV_U4:
9000                 case CEE_CONV_I8:
9001                 case CEE_CONV_U8:
9002                 case CEE_CONV_OVF_I8:
9003                 case CEE_CONV_OVF_U8:
9004                 case CEE_CONV_R_UN:
9005                         CHECK_STACK (1);
9006
9007                         /* Special case this earlier so we have long constants in the IR */
9008                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9009                                 int data = sp [-1]->inst_c0;
9010                                 sp [-1]->opcode = OP_I8CONST;
9011                                 sp [-1]->type = STACK_I8;
9012 #if SIZEOF_REGISTER == 8
9013                                 if ((*ip) == CEE_CONV_U8)
9014                                         sp [-1]->inst_c0 = (guint32)data;
9015                                 else
9016                                         sp [-1]->inst_c0 = data;
9017 #else
9018                                 sp [-1]->inst_ls_word = data;
9019                                 if ((*ip) == CEE_CONV_U8)
9020                                         sp [-1]->inst_ms_word = 0;
9021                                 else
9022                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9023 #endif
9024                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9025                         }
9026                         else {
9027                                 ADD_UNOP (*ip);
9028                         }
9029                         ip++;
9030                         break;
9031                 case CEE_CONV_OVF_I4:
9032                 case CEE_CONV_OVF_I1:
9033                 case CEE_CONV_OVF_I2:
9034                 case CEE_CONV_OVF_I:
9035                 case CEE_CONV_OVF_U:
9036                         CHECK_STACK (1);
9037
9038                         if (sp [-1]->type == STACK_R8) {
9039                                 ADD_UNOP (CEE_CONV_OVF_I8);
9040                                 ADD_UNOP (*ip);
9041                         } else {
9042                                 ADD_UNOP (*ip);
9043                         }
9044                         ip++;
9045                         break;
9046                 case CEE_CONV_OVF_U1:
9047                 case CEE_CONV_OVF_U2:
9048                 case CEE_CONV_OVF_U4:
9049                         CHECK_STACK (1);
9050
9051                         if (sp [-1]->type == STACK_R8) {
9052                                 ADD_UNOP (CEE_CONV_OVF_U8);
9053                                 ADD_UNOP (*ip);
9054                         } else {
9055                                 ADD_UNOP (*ip);
9056                         }
9057                         ip++;
9058                         break;
9059                 case CEE_CONV_OVF_I1_UN:
9060                 case CEE_CONV_OVF_I2_UN:
9061                 case CEE_CONV_OVF_I4_UN:
9062                 case CEE_CONV_OVF_I8_UN:
9063                 case CEE_CONV_OVF_U1_UN:
9064                 case CEE_CONV_OVF_U2_UN:
9065                 case CEE_CONV_OVF_U4_UN:
9066                 case CEE_CONV_OVF_U8_UN:
9067                 case CEE_CONV_OVF_I_UN:
9068                 case CEE_CONV_OVF_U_UN:
9069                 case CEE_CONV_U2:
9070                 case CEE_CONV_U1:
9071                 case CEE_CONV_I:
9072                 case CEE_CONV_U:
9073                         CHECK_STACK (1);
9074                         ADD_UNOP (*ip);
9075                         CHECK_CFG_EXCEPTION;
9076                         ip++;
9077                         break;
9078                 case CEE_ADD_OVF:
9079                 case CEE_ADD_OVF_UN:
9080                 case CEE_MUL_OVF:
9081                 case CEE_MUL_OVF_UN:
9082                 case CEE_SUB_OVF:
9083                 case CEE_SUB_OVF_UN:
9084                         CHECK_STACK (2);
9085                         ADD_BINOP (*ip);
9086                         ip++;
9087                         break;
9088                 case CEE_CPOBJ:
9089                         GSHAREDVT_FAILURE (*ip);
9090                         CHECK_OPSIZE (5);
9091                         CHECK_STACK (2);
9092                         token = read32 (ip + 1);
9093                         klass = mini_get_class (method, token, generic_context);
9094                         CHECK_TYPELOAD (klass);
9095                         sp -= 2;
9096                         if (generic_class_is_reference_type (cfg, klass)) {
9097                                 MonoInst *store, *load;
9098                                 int dreg = alloc_ireg_ref (cfg);
9099
9100                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9101                                 load->flags |= ins_flag;
9102                                 MONO_ADD_INS (cfg->cbb, load);
9103
9104                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9105                                 store->flags |= ins_flag;
9106                                 MONO_ADD_INS (cfg->cbb, store);
9107
9108                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9109                                         emit_write_barrier (cfg, sp [0], sp [1]);
9110                         } else {
9111                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9112                         }
9113                         ins_flag = 0;
9114                         ip += 5;
9115                         break;
9116                 case CEE_LDOBJ: {
9117                         int loc_index = -1;
9118                         int stloc_len = 0;
9119
9120                         CHECK_OPSIZE (5);
9121                         CHECK_STACK (1);
9122                         --sp;
9123                         token = read32 (ip + 1);
9124                         klass = mini_get_class (method, token, generic_context);
9125                         CHECK_TYPELOAD (klass);
9126
9127                         /* Optimize the common ldobj+stloc combination */
9128                         switch (ip [5]) {
9129                         case CEE_STLOC_S:
9130                                 loc_index = ip [6];
9131                                 stloc_len = 2;
9132                                 break;
9133                         case CEE_STLOC_0:
9134                         case CEE_STLOC_1:
9135                         case CEE_STLOC_2:
9136                         case CEE_STLOC_3:
9137                                 loc_index = ip [5] - CEE_STLOC_0;
9138                                 stloc_len = 1;
9139                                 break;
9140                         default:
9141                                 break;
9142                         }
9143
9144                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9145                                 CHECK_LOCAL (loc_index);
9146
9147                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9148                                 ins->dreg = cfg->locals [loc_index]->dreg;
9149                                 ip += 5;
9150                                 ip += stloc_len;
9151                                 break;
9152                         }
9153
9154                         /* Optimize the ldobj+stobj combination */
9155                         /* The reference case ends up being a load+store anyway */
9156                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9157                                 CHECK_STACK (1);
9158
9159                                 sp --;
9160
9161                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9162
9163                                 ip += 5 + 5;
9164                                 ins_flag = 0;
9165                                 break;
9166                         }
9167
9168                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9169                         *sp++ = ins;
9170
9171                         ip += 5;
9172                         ins_flag = 0;
9173                         inline_costs += 1;
9174                         break;
9175                 }
9176                 case CEE_LDSTR:
9177                         CHECK_STACK_OVF (1);
9178                         CHECK_OPSIZE (5);
9179                         n = read32 (ip + 1);
9180
9181                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9182                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9183                                 ins->type = STACK_OBJ;
9184                                 *sp = ins;
9185                         }
9186                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9187                                 MonoInst *iargs [1];
9188
9189                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9190                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9191                         } else {
9192                                 if (cfg->opt & MONO_OPT_SHARED) {
9193                                         MonoInst *iargs [3];
9194
9195                                         if (cfg->compile_aot) {
9196                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9197                                         }
9198                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9199                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9200                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9201                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9202                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9203                                 } else {
9204                                         if (bblock->out_of_line) {
9205                                                 MonoInst *iargs [2];
9206
9207                                                 if (image == mono_defaults.corlib) {
9208                                                         /* 
9209                                                          * Avoid relocations in AOT and save some space by using a 
9210                                                          * version of helper_ldstr specialized to mscorlib.
9211                                                          */
9212                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9213                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9214                                                 } else {
9215                                                         /* Avoid creating the string object */
9216                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9217                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9218                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9219                                                 }
9220                                         } 
9221                                         else
9222                                         if (cfg->compile_aot) {
9223                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9224                                                 *sp = ins;
9225                                                 MONO_ADD_INS (bblock, ins);
9226                                         } 
9227                                         else {
9228                                                 NEW_PCONST (cfg, ins, NULL);
9229                                                 ins->type = STACK_OBJ;
9230                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9231                                                 if (!ins->inst_p0)
9232                                                         OUT_OF_MEMORY_FAILURE;
9233
9234                                                 *sp = ins;
9235                                                 MONO_ADD_INS (bblock, ins);
9236                                         }
9237                                 }
9238                         }
9239
9240                         sp++;
9241                         ip += 5;
9242                         break;
9243                 case CEE_NEWOBJ: {
9244                         MonoInst *iargs [2];
9245                         MonoMethodSignature *fsig;
9246                         MonoInst this_ins;
9247                         MonoInst *alloc;
9248                         MonoInst *vtable_arg = NULL;
9249
9250                         CHECK_OPSIZE (5);
9251                         token = read32 (ip + 1);
9252                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9253                         if (!cmethod || mono_loader_get_last_error ())
9254                                 LOAD_ERROR;
9255                         fsig = mono_method_get_signature (cmethod, image, token);
9256                         if (!fsig)
9257                                 LOAD_ERROR;
9258
9259                         mono_save_token_info (cfg, image, token, cmethod);
9260
9261                         if (!mono_class_init (cmethod->klass))
9262                                 TYPE_LOAD_ERROR (cmethod->klass);
9263
9264                         context_used = mini_method_check_context_used (cfg, cmethod);
9265
9266                         if (mono_security_cas_enabled ()) {
9267                                 if (check_linkdemand (cfg, method, cmethod))
9268                                         INLINE_FAILURE ("linkdemand");
9269                                 CHECK_CFG_EXCEPTION;
9270                         } else if (mono_security_core_clr_enabled ()) {
9271                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9272                         }
9273
9274                         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)) {
9275                                 emit_generic_class_init (cfg, cmethod->klass);
9276                                 CHECK_TYPELOAD (cmethod->klass);
9277                         }
9278
9279                         /*
9280                         if (cfg->gsharedvt) {
9281                                 if (mini_is_gsharedvt_variable_signature (sig))
9282                                         GSHAREDVT_FAILURE (*ip);
9283                         }
9284                         */
9285
9286                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9287                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9288                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9289                                         mono_class_vtable (cfg->domain, cmethod->klass);
9290                                         CHECK_TYPELOAD (cmethod->klass);
9291
9292                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9293                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9294                                 } else {
9295                                         if (context_used) {
9296                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9297                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9298                                         } else {
9299                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9300
9301                                                 CHECK_TYPELOAD (cmethod->klass);
9302                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9303                                         }
9304                                 }
9305                         }
9306
9307                         n = fsig->param_count;
9308                         CHECK_STACK (n);
9309
9310                         /* 
9311                          * Generate smaller code for the common newobj <exception> instruction in
9312                          * argument checking code.
9313                          */
9314                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9315                                 is_exception_class (cmethod->klass) && n <= 2 &&
9316                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9317                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9318                                 MonoInst *iargs [3];
9319
9320                                 g_assert (!vtable_arg);
9321
9322                                 sp -= n;
9323
9324                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9325                                 switch (n) {
9326                                 case 0:
9327                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9328                                         break;
9329                                 case 1:
9330                                         iargs [1] = sp [0];
9331                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9332                                         break;
9333                                 case 2:
9334                                         iargs [1] = sp [0];
9335                                         iargs [2] = sp [1];
9336                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9337                                         break;
9338                                 default:
9339                                         g_assert_not_reached ();
9340                                 }
9341
9342                                 ip += 5;
9343                                 inline_costs += 5;
9344                                 break;
9345                         }
9346
9347                         /* move the args to allow room for 'this' in the first position */
9348                         while (n--) {
9349                                 --sp;
9350                                 sp [1] = sp [0];
9351                         }
9352
9353                         /* check_call_signature () requires sp[0] to be set */
9354                         this_ins.type = STACK_OBJ;
9355                         sp [0] = &this_ins;
9356                         if (check_call_signature (cfg, fsig, sp))
9357                                 UNVERIFIED;
9358
9359                         iargs [0] = NULL;
9360
9361                         if (mini_class_is_system_array (cmethod->klass)) {
9362                                 g_assert (!vtable_arg);
9363
9364                                 *sp = emit_get_rgctx_method (cfg, context_used,
9365                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9366
9367                                 /* Avoid varargs in the common case */
9368                                 if (fsig->param_count == 1)
9369                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9370                                 else if (fsig->param_count == 2)
9371                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9372                                 else if (fsig->param_count == 3)
9373                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9374                                 else if (fsig->param_count == 4)
9375                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9376                                 else
9377                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9378                         } else if (cmethod->string_ctor) {
9379                                 g_assert (!context_used);
9380                                 g_assert (!vtable_arg);
9381                                 /* we simply pass a null pointer */
9382                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9383                                 /* now call the string ctor */
9384                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9385                         } else {
9386                                 MonoInst* callvirt_this_arg = NULL;
9387                                 
9388                                 if (cmethod->klass->valuetype) {
9389                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9390                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9391                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9392
9393                                         alloc = NULL;
9394
9395                                         /* 
9396                                          * The code generated by mini_emit_virtual_call () expects
9397                                          * iargs [0] to be a boxed instance, but luckily the vcall
9398                                          * will be transformed into a normal call there.
9399                                          */
9400                                 } else if (context_used) {
9401                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9402                                         *sp = alloc;
9403                                 } else {
9404                                         MonoVTable *vtable = NULL;
9405
9406                                         if (!cfg->compile_aot)
9407                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9408                                         CHECK_TYPELOAD (cmethod->klass);
9409
9410                                         /*
9411                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9412                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9413                                          * As a workaround, we call class cctors before allocating objects.
9414                                          */
9415                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9416                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9417                                                 if (cfg->verbose_level > 2)
9418                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9419                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9420                                         }
9421
9422                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9423                                         *sp = alloc;
9424                                 }
9425                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9426
9427                                 if (alloc)
9428                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9429
9430                                 /* Now call the actual ctor */
9431                                 /* Avoid virtual calls to ctors if possible */
9432                                 if (mono_class_is_marshalbyref (cmethod->klass))
9433                                         callvirt_this_arg = sp [0];
9434
9435
9436                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9437                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9438                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9439                                                 *sp = ins;
9440                                                 sp++;
9441                                         }
9442
9443                                         CHECK_CFG_EXCEPTION;
9444                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9445                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9446                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9447                                     !g_list_find (dont_inline, cmethod)) {
9448                                         int costs;
9449
9450                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9451                                                 cfg->real_offset += 5;
9452                                                 bblock = cfg->cbb;
9453
9454                                                 inline_costs += costs - 5;
9455                                         } else {
9456                                                 INLINE_FAILURE ("inline failure");
9457                                                 // FIXME-VT: Clean this up
9458                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9459                                                         GSHAREDVT_FAILURE(*ip);
9460                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9461                                         }
9462                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9463                                         MonoInst *addr;
9464
9465                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9466                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9467                                 } else if (context_used &&
9468                                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
9469                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
9470                                         MonoInst *cmethod_addr;
9471
9472                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9473                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9474
9475                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9476                                 } else {
9477                                         INLINE_FAILURE ("ctor call");
9478                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9479                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9480                                 }
9481                         }
9482
9483                         if (alloc == NULL) {
9484                                 /* Valuetype */
9485                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9486                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9487                                 *sp++= ins;
9488                         }
9489                         else
9490                                 *sp++ = alloc;
9491                         
9492                         ip += 5;
9493                         inline_costs += 5;
9494                         break;
9495                 }
9496                 case CEE_CASTCLASS:
9497                         CHECK_STACK (1);
9498                         --sp;
9499                         CHECK_OPSIZE (5);
9500                         token = read32 (ip + 1);
9501                         klass = mini_get_class (method, token, generic_context);
9502                         CHECK_TYPELOAD (klass);
9503                         if (sp [0]->type != STACK_OBJ)
9504                                 UNVERIFIED;
9505
9506                         context_used = mini_class_check_context_used (cfg, klass);
9507
9508                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9509                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9510                                 MonoInst *args [3];
9511
9512                                 /* obj */
9513                                 args [0] = *sp;
9514
9515                                 /* klass */
9516                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9517
9518                                 /* inline cache*/
9519                                 if (cfg->compile_aot)
9520                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9521                                 else
9522                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9523
9524                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9525
9526                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9527                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9528                                 reset_cast_details (cfg);
9529                                 ip += 5;
9530                                 inline_costs += 2;
9531                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9532                                 MonoMethod *mono_castclass;
9533                                 MonoInst *iargs [1];
9534                                 int costs;
9535
9536                                 mono_castclass = mono_marshal_get_castclass (klass); 
9537                                 iargs [0] = sp [0];
9538                                 
9539                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9540                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9541                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9542                                 reset_cast_details (cfg);
9543                                 CHECK_CFG_EXCEPTION;
9544                                 g_assert (costs > 0);
9545                                 
9546                                 ip += 5;
9547                                 cfg->real_offset += 5;
9548                                 bblock = cfg->cbb;
9549
9550                                 *sp++ = iargs [0];
9551
9552                                 inline_costs += costs;
9553                         }
9554                         else {
9555                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9556                                 CHECK_CFG_EXCEPTION;
9557                                 bblock = cfg->cbb;
9558                                 *sp ++ = ins;
9559                                 ip += 5;
9560                         }
9561                         break;
9562                 case CEE_ISINST: {
9563                         CHECK_STACK (1);
9564                         --sp;
9565                         CHECK_OPSIZE (5);
9566                         token = read32 (ip + 1);
9567                         klass = mini_get_class (method, token, generic_context);
9568                         CHECK_TYPELOAD (klass);
9569                         if (sp [0]->type != STACK_OBJ)
9570                                 UNVERIFIED;
9571  
9572                         context_used = mini_class_check_context_used (cfg, klass);
9573
9574                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9575                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9576                                 MonoInst *args [3];
9577
9578                                 /* obj */
9579                                 args [0] = *sp;
9580
9581                                 /* klass */
9582                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9583
9584                                 /* inline cache*/
9585                                 if (cfg->compile_aot)
9586                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9587                                 else
9588                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9589
9590                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9591                                 ip += 5;
9592                                 inline_costs += 2;
9593                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9594                                 MonoMethod *mono_isinst;
9595                                 MonoInst *iargs [1];
9596                                 int costs;
9597
9598                                 mono_isinst = mono_marshal_get_isinst (klass); 
9599                                 iargs [0] = sp [0];
9600
9601                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9602                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9603                                 CHECK_CFG_EXCEPTION;
9604                                 g_assert (costs > 0);
9605                                 
9606                                 ip += 5;
9607                                 cfg->real_offset += 5;
9608                                 bblock = cfg->cbb;
9609
9610                                 *sp++= iargs [0];
9611
9612                                 inline_costs += costs;
9613                         }
9614                         else {
9615                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9616                                 CHECK_CFG_EXCEPTION;
9617                                 bblock = cfg->cbb;
9618                                 *sp ++ = ins;
9619                                 ip += 5;
9620                         }
9621                         break;
9622                 }
9623                 case CEE_UNBOX_ANY: {
9624                         CHECK_STACK (1);
9625                         --sp;
9626                         CHECK_OPSIZE (5);
9627                         token = read32 (ip + 1);
9628                         klass = mini_get_class (method, token, generic_context);
9629                         CHECK_TYPELOAD (klass);
9630  
9631                         mono_save_token_info (cfg, image, token, klass);
9632
9633                         context_used = mini_class_check_context_used (cfg, klass);
9634
9635                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9636                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9637                                 sp ++;
9638
9639                                 ip += 5;
9640                                 inline_costs += 2;
9641                                 break;
9642                         }
9643
9644                         if (generic_class_is_reference_type (cfg, klass)) {
9645                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9646                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9647                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9648                                         MonoInst *args [3];
9649
9650                                         /* obj */
9651                                         args [0] = *sp;
9652
9653                                         /* klass */
9654                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9655
9656                                         /* inline cache*/
9657                                         /*FIXME AOT support*/
9658                                         if (cfg->compile_aot)
9659                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9660                                         else
9661                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9662
9663                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9664                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9665                                         ip += 5;
9666                                         inline_costs += 2;
9667                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9668                                         MonoMethod *mono_castclass;
9669                                         MonoInst *iargs [1];
9670                                         int costs;
9671
9672                                         mono_castclass = mono_marshal_get_castclass (klass); 
9673                                         iargs [0] = sp [0];
9674
9675                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9676                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9677                                         CHECK_CFG_EXCEPTION;
9678                                         g_assert (costs > 0);
9679                                 
9680                                         ip += 5;
9681                                         cfg->real_offset += 5;
9682                                         bblock = cfg->cbb;
9683
9684                                         *sp++ = iargs [0];
9685                                         inline_costs += costs;
9686                                 } else {
9687                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9688                                         CHECK_CFG_EXCEPTION;
9689                                         bblock = cfg->cbb;
9690                                         *sp ++ = ins;
9691                                         ip += 5;
9692                                 }
9693                                 break;
9694                         }
9695
9696                         if (mono_class_is_nullable (klass)) {
9697                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9698                                 *sp++= ins;
9699                                 ip += 5;
9700                                 break;
9701                         }
9702
9703                         /* UNBOX */
9704                         ins = handle_unbox (cfg, klass, sp, context_used);
9705                         *sp = ins;
9706
9707                         ip += 5;
9708
9709                         /* LDOBJ */
9710                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9711                         *sp++ = ins;
9712
9713                         inline_costs += 2;
9714                         break;
9715                 }
9716                 case CEE_BOX: {
9717                         MonoInst *val;
9718
9719                         CHECK_STACK (1);
9720                         --sp;
9721                         val = *sp;
9722                         CHECK_OPSIZE (5);
9723                         token = read32 (ip + 1);
9724                         klass = mini_get_class (method, token, generic_context);
9725                         CHECK_TYPELOAD (klass);
9726
9727                         mono_save_token_info (cfg, image, token, klass);
9728
9729                         context_used = mini_class_check_context_used (cfg, klass);
9730
9731                         if (generic_class_is_reference_type (cfg, klass)) {
9732                                 *sp++ = val;
9733                                 ip += 5;
9734                                 break;
9735                         }
9736
9737                         if (klass == mono_defaults.void_class)
9738                                 UNVERIFIED;
9739                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9740                                 UNVERIFIED;
9741                         /* frequent check in generic code: box (struct), brtrue */
9742
9743                         // FIXME: LLVM can't handle the inconsistent bb linking
9744                         if (!mono_class_is_nullable (klass) &&
9745                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9746                                 (ip [5] == CEE_BRTRUE || 
9747                                  ip [5] == CEE_BRTRUE_S ||
9748                                  ip [5] == CEE_BRFALSE ||
9749                                  ip [5] == CEE_BRFALSE_S)) {
9750                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9751                                 int dreg;
9752                                 MonoBasicBlock *true_bb, *false_bb;
9753
9754                                 ip += 5;
9755
9756                                 if (cfg->verbose_level > 3) {
9757                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9758                                         printf ("<box+brtrue opt>\n");
9759                                 }
9760
9761                                 switch (*ip) {
9762                                 case CEE_BRTRUE_S:
9763                                 case CEE_BRFALSE_S:
9764                                         CHECK_OPSIZE (2);
9765                                         ip++;
9766                                         target = ip + 1 + (signed char)(*ip);
9767                                         ip++;
9768                                         break;
9769                                 case CEE_BRTRUE:
9770                                 case CEE_BRFALSE:
9771                                         CHECK_OPSIZE (5);
9772                                         ip++;
9773                                         target = ip + 4 + (gint)(read32 (ip));
9774                                         ip += 4;
9775                                         break;
9776                                 default:
9777                                         g_assert_not_reached ();
9778                                 }
9779
9780                                 /* 
9781                                  * We need to link both bblocks, since it is needed for handling stack
9782                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9783                                  * Branching to only one of them would lead to inconsistencies, so
9784                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9785                                  */
9786                                 GET_BBLOCK (cfg, true_bb, target);
9787                                 GET_BBLOCK (cfg, false_bb, ip);
9788
9789                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9790                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9791
9792                                 if (sp != stack_start) {
9793                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9794                                         sp = stack_start;
9795                                         CHECK_UNVERIFIABLE (cfg);
9796                                 }
9797
9798                                 if (COMPILE_LLVM (cfg)) {
9799                                         dreg = alloc_ireg (cfg);
9800                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9801                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9802
9803                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9804                                 } else {
9805                                         /* The JIT can't eliminate the iconst+compare */
9806                                         MONO_INST_NEW (cfg, ins, OP_BR);
9807                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9808                                         MONO_ADD_INS (cfg->cbb, ins);
9809                                 }
9810
9811                                 start_new_bblock = 1;
9812                                 break;
9813                         }
9814
9815                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9816
9817                         CHECK_CFG_EXCEPTION;
9818                         ip += 5;
9819                         inline_costs += 1;
9820                         break;
9821                 }
9822                 case CEE_UNBOX: {
9823                         CHECK_STACK (1);
9824                         --sp;
9825                         CHECK_OPSIZE (5);
9826                         token = read32 (ip + 1);
9827                         klass = mini_get_class (method, token, generic_context);
9828                         CHECK_TYPELOAD (klass);
9829
9830                         mono_save_token_info (cfg, image, token, klass);
9831
9832                         context_used = mini_class_check_context_used (cfg, klass);
9833
9834                         if (mono_class_is_nullable (klass)) {
9835                                 MonoInst *val;
9836
9837                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9838                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9839
9840                                 *sp++= ins;
9841                         } else {
9842                                 ins = handle_unbox (cfg, klass, sp, context_used);
9843                                 *sp++ = ins;
9844                         }
9845                         ip += 5;
9846                         inline_costs += 2;
9847                         break;
9848                 }
9849                 case CEE_LDFLD:
9850                 case CEE_LDFLDA:
9851                 case CEE_STFLD:
9852                 case CEE_LDSFLD:
9853                 case CEE_LDSFLDA:
9854                 case CEE_STSFLD: {
9855                         MonoClassField *field;
9856 #ifndef DISABLE_REMOTING
9857                         int costs;
9858 #endif
9859                         guint foffset;
9860                         gboolean is_instance;
9861                         int op;
9862                         gpointer addr = NULL;
9863                         gboolean is_special_static;
9864                         MonoType *ftype;
9865                         MonoInst *store_val = NULL;
9866                         MonoInst *thread_ins;
9867
9868                         op = *ip;
9869                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
9870                         if (is_instance) {
9871                                 if (op == CEE_STFLD) {
9872                                         CHECK_STACK (2);
9873                                         sp -= 2;
9874                                         store_val = sp [1];
9875                                 } else {
9876                                         CHECK_STACK (1);
9877                                         --sp;
9878                                 }
9879                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
9880                                         UNVERIFIED;
9881                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
9882                                         UNVERIFIED;
9883                         } else {
9884                                 if (op == CEE_STSFLD) {
9885                                         CHECK_STACK (1);
9886                                         sp--;
9887                                         store_val = sp [0];
9888                                 }
9889                         }
9890
9891                         CHECK_OPSIZE (5);
9892                         token = read32 (ip + 1);
9893                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
9894                                 field = mono_method_get_wrapper_data (method, token);
9895                                 klass = field->parent;
9896                         }
9897                         else {
9898                                 field = mono_field_from_token (image, token, &klass, generic_context);
9899                         }
9900                         if (!field)
9901                                 LOAD_ERROR;
9902                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
9903                                 FIELD_ACCESS_FAILURE;
9904                         mono_class_init (klass);
9905
9906                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
9907                                 UNVERIFIED;
9908
9909                         /* if the class is Critical then transparent code cannot access it's fields */
9910                         if (!is_instance && mono_security_core_clr_enabled ())
9911                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9912
9913                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
9914                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
9915                         if (mono_security_core_clr_enabled ())
9916                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9917                         */
9918
9919                         /*
9920                          * LDFLD etc. is usable on static fields as well, so convert those cases to
9921                          * the static case.
9922                          */
9923                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9924                                 switch (op) {
9925                                 case CEE_LDFLD:
9926                                         op = CEE_LDSFLD;
9927                                         break;
9928                                 case CEE_STFLD:
9929                                         op = CEE_STSFLD;
9930                                         break;
9931                                 case CEE_LDFLDA:
9932                                         op = CEE_LDSFLDA;
9933                                         break;
9934                                 default:
9935                                         g_assert_not_reached ();
9936                                 }
9937                                 is_instance = FALSE;
9938                         }
9939
9940                         context_used = mini_class_check_context_used (cfg, klass);
9941
9942                         /* INSTANCE CASE */
9943
9944                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
9945                         if (op == CEE_STFLD) {
9946                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
9947                                         UNVERIFIED;
9948 #ifndef DISABLE_REMOTING
9949                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
9950                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
9951                                         MonoInst *iargs [5];
9952
9953                                         GSHAREDVT_FAILURE (op);
9954
9955                                         iargs [0] = sp [0];
9956                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9957                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9958                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
9959                                                     field->offset);
9960                                         iargs [4] = sp [1];
9961
9962                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9963                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
9964                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
9965                                                 CHECK_CFG_EXCEPTION;
9966                                                 g_assert (costs > 0);
9967                                                       
9968                                                 cfg->real_offset += 5;
9969                                                 bblock = cfg->cbb;
9970
9971                                                 inline_costs += costs;
9972                                         } else {
9973                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
9974                                         }
9975                                 } else
9976 #endif
9977                                 {
9978                                         MonoInst *store;
9979
9980                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9981
9982                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9983                                                 MonoInst *offset_ins;
9984
9985                                                 context_used = mini_class_check_context_used (cfg, klass);
9986
9987                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9988                                                 dreg = alloc_ireg_mp (cfg);
9989                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9990                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
9991                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
9992                                         } else {
9993                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
9994                                         }
9995                                         if (sp [0]->opcode != OP_LDADDR)
9996                                                 store->flags |= MONO_INST_FAULT;
9997
9998                                 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)) {
9999                                         /* insert call to write barrier */
10000                                         MonoInst *ptr;
10001                                         int dreg;
10002
10003                                         dreg = alloc_ireg_mp (cfg);
10004                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10005                                         emit_write_barrier (cfg, ptr, sp [1]);
10006                                 }
10007
10008                                         store->flags |= ins_flag;
10009                                 }
10010                                 ins_flag = 0;
10011                                 ip += 5;
10012                                 break;
10013                         }
10014
10015 #ifndef DISABLE_REMOTING
10016                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10017                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10018                                 MonoInst *iargs [4];
10019
10020                                 GSHAREDVT_FAILURE (op);
10021
10022                                 iargs [0] = sp [0];
10023                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10024                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10025                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10026                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10027                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10028                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
10029                                         CHECK_CFG_EXCEPTION;
10030                                         bblock = cfg->cbb;
10031                                         g_assert (costs > 0);
10032                                                       
10033                                         cfg->real_offset += 5;
10034
10035                                         *sp++ = iargs [0];
10036
10037                                         inline_costs += costs;
10038                                 } else {
10039                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10040                                         *sp++ = ins;
10041                                 }
10042                         } else 
10043 #endif
10044                         if (is_instance) {
10045                                 if (sp [0]->type == STACK_VTYPE) {
10046                                         MonoInst *var;
10047
10048                                         /* Have to compute the address of the variable */
10049
10050                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10051                                         if (!var)
10052                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10053                                         else
10054                                                 g_assert (var->klass == klass);
10055                                         
10056                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10057                                         sp [0] = ins;
10058                                 }
10059
10060                                 if (op == CEE_LDFLDA) {
10061                                         if (is_magic_tls_access (field)) {
10062                                                 GSHAREDVT_FAILURE (*ip);
10063                                                 ins = sp [0];
10064                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10065                                         } else {
10066                                                 if (sp [0]->type == STACK_OBJ) {
10067                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10068                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10069                                                 }
10070
10071                                                 dreg = alloc_ireg_mp (cfg);
10072
10073                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10074                                                         MonoInst *offset_ins;
10075
10076                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10077                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10078                                                 } else {
10079                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10080                                                 }
10081                                                 ins->klass = mono_class_from_mono_type (field->type);
10082                                                 ins->type = STACK_MP;
10083                                                 *sp++ = ins;
10084                                         }
10085                                 } else {
10086                                         MonoInst *load;
10087
10088                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10089
10090                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10091                                                 MonoInst *offset_ins;
10092
10093                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10094                                                 dreg = alloc_ireg_mp (cfg);
10095                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10096                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10097                                         } else {
10098                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10099                                         }
10100                                         load->flags |= ins_flag;
10101                                         if (sp [0]->opcode != OP_LDADDR)
10102                                                 load->flags |= MONO_INST_FAULT;
10103                                         *sp++ = load;
10104                                 }
10105                         }
10106
10107                         if (is_instance) {
10108                                 ins_flag = 0;
10109                                 ip += 5;
10110                                 break;
10111                         }
10112
10113                         /* STATIC CASE */
10114
10115                         /*
10116                          * We can only support shared generic static
10117                          * field access on architectures where the
10118                          * trampoline code has been extended to handle
10119                          * the generic class init.
10120                          */
10121 #ifndef MONO_ARCH_VTABLE_REG
10122                         GENERIC_SHARING_FAILURE (op);
10123 #endif
10124
10125                         context_used = mini_class_check_context_used (cfg, klass);
10126
10127                         ftype = mono_field_get_type (field);
10128
10129                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10130                                 UNVERIFIED;
10131
10132                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10133                          * to be called here.
10134                          */
10135                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10136                                 mono_class_vtable (cfg->domain, klass);
10137                                 CHECK_TYPELOAD (klass);
10138                         }
10139                         mono_domain_lock (cfg->domain);
10140                         if (cfg->domain->special_static_fields)
10141                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10142                         mono_domain_unlock (cfg->domain);
10143
10144                         is_special_static = mono_class_field_is_special_static (field);
10145
10146                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10147                                 thread_ins = mono_get_thread_intrinsic (cfg);
10148                         else
10149                                 thread_ins = NULL;
10150
10151                         /* Generate IR to compute the field address */
10152                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10153                                 /*
10154                                  * Fast access to TLS data
10155                                  * Inline version of get_thread_static_data () in
10156                                  * threads.c.
10157                                  */
10158                                 guint32 offset;
10159                                 int idx, static_data_reg, array_reg, dreg;
10160
10161                                 GSHAREDVT_FAILURE (op);
10162
10163                                 // offset &= 0x7fffffff;
10164                                 // idx = (offset >> 24) - 1;
10165                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10166                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10167                                 static_data_reg = alloc_ireg (cfg);
10168                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10169
10170                                 if (cfg->compile_aot) {
10171                                         int offset_reg, offset2_reg, idx_reg;
10172
10173                                         /* For TLS variables, this will return the TLS offset */
10174                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10175                                         offset_reg = ins->dreg;
10176                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10177                                         idx_reg = alloc_ireg (cfg);
10178                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10179                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10180                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10181                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10182                                         array_reg = alloc_ireg (cfg);
10183                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10184                                         offset2_reg = alloc_ireg (cfg);
10185                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10186                                         dreg = alloc_ireg (cfg);
10187                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10188                                 } else {
10189                                         offset = (gsize)addr & 0x7fffffff;
10190                                         idx = (offset >> 24) - 1;
10191
10192                                         array_reg = alloc_ireg (cfg);
10193                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10194                                         dreg = alloc_ireg (cfg);
10195                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10196                                 }
10197                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10198                                         (cfg->compile_aot && is_special_static) ||
10199                                         (context_used && is_special_static)) {
10200                                 MonoInst *iargs [2];
10201
10202                                 g_assert (field->parent);
10203                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10204                                 if (context_used) {
10205                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10206                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10207                                 } else {
10208                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10209                                 }
10210                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10211                         } else if (context_used) {
10212                                 MonoInst *static_data;
10213
10214                                 /*
10215                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10216                                         method->klass->name_space, method->klass->name, method->name,
10217                                         depth, field->offset);
10218                                 */
10219
10220                                 if (mono_class_needs_cctor_run (klass, method))
10221                                         emit_generic_class_init (cfg, klass);
10222
10223                                 /*
10224                                  * The pointer we're computing here is
10225                                  *
10226                                  *   super_info.static_data + field->offset
10227                                  */
10228                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10229                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10230
10231                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10232                                         MonoInst *offset_ins;
10233
10234                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10235                                         dreg = alloc_ireg_mp (cfg);
10236                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10237                                 } else if (field->offset == 0) {
10238                                         ins = static_data;
10239                                 } else {
10240                                         int addr_reg = mono_alloc_preg (cfg);
10241                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10242                                 }
10243                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10244                                 MonoInst *iargs [2];
10245
10246                                 g_assert (field->parent);
10247                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10248                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10249                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10250                         } else {
10251                                 MonoVTable *vtable = NULL;
10252
10253                                 if (!cfg->compile_aot)
10254                                         vtable = mono_class_vtable (cfg->domain, klass);
10255                                 CHECK_TYPELOAD (klass);
10256
10257                                 if (!addr) {
10258                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10259                                                 if (!(g_slist_find (class_inits, klass))) {
10260                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10261                                                         if (cfg->verbose_level > 2)
10262                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10263                                                         class_inits = g_slist_prepend (class_inits, klass);
10264                                                 }
10265                                         } else {
10266                                                 if (cfg->run_cctors) {
10267                                                         MonoException *ex;
10268                                                         /* This makes so that inline cannot trigger */
10269                                                         /* .cctors: too many apps depend on them */
10270                                                         /* running with a specific order... */
10271                                                         g_assert (vtable);
10272                                                         if (! vtable->initialized)
10273                                                                 INLINE_FAILURE ("class init");
10274                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10275                                                         if (ex) {
10276                                                                 set_exception_object (cfg, ex);
10277                                                                 goto exception_exit;
10278                                                         }
10279                                                 }
10280                                         }
10281                                         if (cfg->compile_aot)
10282                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10283                                         else {
10284                                                 g_assert (vtable);
10285                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10286                                                 g_assert (addr);
10287                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10288                                         }
10289                                 } else {
10290                                         MonoInst *iargs [1];
10291                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10292                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10293                                 }
10294                         }
10295
10296                         /* Generate IR to do the actual load/store operation */
10297
10298                         if (op == CEE_LDSFLDA) {
10299                                 ins->klass = mono_class_from_mono_type (ftype);
10300                                 ins->type = STACK_PTR;
10301                                 *sp++ = ins;
10302                         } else if (op == CEE_STSFLD) {
10303                                 MonoInst *store;
10304
10305                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10306                                 store->flags |= ins_flag;
10307                         } else {
10308                                 gboolean is_const = FALSE;
10309                                 MonoVTable *vtable = NULL;
10310                                 gpointer addr = NULL;
10311
10312                                 if (!context_used) {
10313                                         vtable = mono_class_vtable (cfg->domain, klass);
10314                                         CHECK_TYPELOAD (klass);
10315                                 }
10316                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10317                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10318                                         int ro_type = ftype->type;
10319                                         if (!addr)
10320                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10321                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10322                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10323                                         }
10324
10325                                         GSHAREDVT_FAILURE (op);
10326
10327                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10328                                         is_const = TRUE;
10329                                         switch (ro_type) {
10330                                         case MONO_TYPE_BOOLEAN:
10331                                         case MONO_TYPE_U1:
10332                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10333                                                 sp++;
10334                                                 break;
10335                                         case MONO_TYPE_I1:
10336                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10337                                                 sp++;
10338                                                 break;                                          
10339                                         case MONO_TYPE_CHAR:
10340                                         case MONO_TYPE_U2:
10341                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10342                                                 sp++;
10343                                                 break;
10344                                         case MONO_TYPE_I2:
10345                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10346                                                 sp++;
10347                                                 break;
10348                                                 break;
10349                                         case MONO_TYPE_I4:
10350                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10351                                                 sp++;
10352                                                 break;                                          
10353                                         case MONO_TYPE_U4:
10354                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10355                                                 sp++;
10356                                                 break;
10357                                         case MONO_TYPE_I:
10358                                         case MONO_TYPE_U:
10359                                         case MONO_TYPE_PTR:
10360                                         case MONO_TYPE_FNPTR:
10361                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10362                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10363                                                 sp++;
10364                                                 break;
10365                                         case MONO_TYPE_STRING:
10366                                         case MONO_TYPE_OBJECT:
10367                                         case MONO_TYPE_CLASS:
10368                                         case MONO_TYPE_SZARRAY:
10369                                         case MONO_TYPE_ARRAY:
10370                                                 if (!mono_gc_is_moving ()) {
10371                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10372                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10373                                                         sp++;
10374                                                 } else {
10375                                                         is_const = FALSE;
10376                                                 }
10377                                                 break;
10378                                         case MONO_TYPE_I8:
10379                                         case MONO_TYPE_U8:
10380                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10381                                                 sp++;
10382                                                 break;
10383                                         case MONO_TYPE_R4:
10384                                         case MONO_TYPE_R8:
10385                                         case MONO_TYPE_VALUETYPE:
10386                                         default:
10387                                                 is_const = FALSE;
10388                                                 break;
10389                                         }
10390                                 }
10391
10392                                 if (!is_const) {
10393                                         MonoInst *load;
10394
10395                                         CHECK_STACK_OVF (1);
10396
10397                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10398                                         load->flags |= ins_flag;
10399                                         ins_flag = 0;
10400                                         *sp++ = load;
10401                                 }
10402                         }
10403                         ins_flag = 0;
10404                         ip += 5;
10405                         break;
10406                 }
10407                 case CEE_STOBJ:
10408                         CHECK_STACK (2);
10409                         sp -= 2;
10410                         CHECK_OPSIZE (5);
10411                         token = read32 (ip + 1);
10412                         klass = mini_get_class (method, token, generic_context);
10413                         CHECK_TYPELOAD (klass);
10414                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10415                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10416                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10417                                         generic_class_is_reference_type (cfg, klass)) {
10418                                 /* insert call to write barrier */
10419                                 emit_write_barrier (cfg, sp [0], sp [1]);
10420                         }
10421                         ins_flag = 0;
10422                         ip += 5;
10423                         inline_costs += 1;
10424                         break;
10425
10426                         /*
10427                          * Array opcodes
10428                          */
10429                 case CEE_NEWARR: {
10430                         MonoInst *len_ins;
10431                         const char *data_ptr;
10432                         int data_size = 0;
10433                         guint32 field_token;
10434
10435                         CHECK_STACK (1);
10436                         --sp;
10437
10438                         CHECK_OPSIZE (5);
10439                         token = read32 (ip + 1);
10440
10441                         klass = mini_get_class (method, token, generic_context);
10442                         CHECK_TYPELOAD (klass);
10443
10444                         context_used = mini_class_check_context_used (cfg, klass);
10445
10446                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10447                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10448                                 ins->sreg1 = sp [0]->dreg;
10449                                 ins->type = STACK_I4;
10450                                 ins->dreg = alloc_ireg (cfg);
10451                                 MONO_ADD_INS (cfg->cbb, ins);
10452                                 *sp = mono_decompose_opcode (cfg, ins);
10453                         }
10454
10455                         if (context_used) {
10456                                 MonoInst *args [3];
10457                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10458                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10459
10460                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10461
10462                                 /* vtable */
10463                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10464                                         array_class, MONO_RGCTX_INFO_VTABLE);
10465                                 /* array len */
10466                                 args [1] = sp [0];
10467
10468                                 if (managed_alloc)
10469                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10470                                 else
10471                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10472                         } else {
10473                                 if (cfg->opt & MONO_OPT_SHARED) {
10474                                         /* Decompose now to avoid problems with references to the domainvar */
10475                                         MonoInst *iargs [3];
10476
10477                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10478                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10479                                         iargs [2] = sp [0];
10480
10481                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10482                                 } else {
10483                                         /* Decompose later since it is needed by abcrem */
10484                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10485                                         mono_class_vtable (cfg->domain, array_type);
10486                                         CHECK_TYPELOAD (array_type);
10487
10488                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10489                                         ins->dreg = alloc_ireg_ref (cfg);
10490                                         ins->sreg1 = sp [0]->dreg;
10491                                         ins->inst_newa_class = klass;
10492                                         ins->type = STACK_OBJ;
10493                                         ins->klass = array_type;
10494                                         MONO_ADD_INS (cfg->cbb, ins);
10495                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10496                                         cfg->cbb->has_array_access = TRUE;
10497
10498                                         /* Needed so mono_emit_load_get_addr () gets called */
10499                                         mono_get_got_var (cfg);
10500                                 }
10501                         }
10502
10503                         len_ins = sp [0];
10504                         ip += 5;
10505                         *sp++ = ins;
10506                         inline_costs += 1;
10507
10508                         /* 
10509                          * we inline/optimize the initialization sequence if possible.
10510                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10511                          * for small sizes open code the memcpy
10512                          * ensure the rva field is big enough
10513                          */
10514                         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))) {
10515                                 MonoMethod *memcpy_method = get_memcpy_method ();
10516                                 MonoInst *iargs [3];
10517                                 int add_reg = alloc_ireg_mp (cfg);
10518
10519                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10520                                 if (cfg->compile_aot) {
10521                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10522                                 } else {
10523                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10524                                 }
10525                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10526                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10527                                 ip += 11;
10528                         }
10529
10530                         break;
10531                 }
10532                 case CEE_LDLEN:
10533                         CHECK_STACK (1);
10534                         --sp;
10535                         if (sp [0]->type != STACK_OBJ)
10536                                 UNVERIFIED;
10537
10538                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10539                         ins->dreg = alloc_preg (cfg);
10540                         ins->sreg1 = sp [0]->dreg;
10541                         ins->type = STACK_I4;
10542                         /* This flag will be inherited by the decomposition */
10543                         ins->flags |= MONO_INST_FAULT;
10544                         MONO_ADD_INS (cfg->cbb, ins);
10545                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10546                         cfg->cbb->has_array_access = TRUE;
10547                         ip ++;
10548                         *sp++ = ins;
10549                         break;
10550                 case CEE_LDELEMA:
10551                         CHECK_STACK (2);
10552                         sp -= 2;
10553                         CHECK_OPSIZE (5);
10554                         if (sp [0]->type != STACK_OBJ)
10555                                 UNVERIFIED;
10556
10557                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10558
10559                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10560                         CHECK_TYPELOAD (klass);
10561                         /* we need to make sure that this array is exactly the type it needs
10562                          * to be for correctness. the wrappers are lax with their usage
10563                          * so we need to ignore them here
10564                          */
10565                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10566                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10567                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10568                                 CHECK_TYPELOAD (array_class);
10569                         }
10570
10571                         readonly = FALSE;
10572                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10573                         *sp++ = ins;
10574                         ip += 5;
10575                         break;
10576                 case CEE_LDELEM:
10577                 case CEE_LDELEM_I1:
10578                 case CEE_LDELEM_U1:
10579                 case CEE_LDELEM_I2:
10580                 case CEE_LDELEM_U2:
10581                 case CEE_LDELEM_I4:
10582                 case CEE_LDELEM_U4:
10583                 case CEE_LDELEM_I8:
10584                 case CEE_LDELEM_I:
10585                 case CEE_LDELEM_R4:
10586                 case CEE_LDELEM_R8:
10587                 case CEE_LDELEM_REF: {
10588                         MonoInst *addr;
10589
10590                         CHECK_STACK (2);
10591                         sp -= 2;
10592
10593                         if (*ip == CEE_LDELEM) {
10594                                 CHECK_OPSIZE (5);
10595                                 token = read32 (ip + 1);
10596                                 klass = mini_get_class (method, token, generic_context);
10597                                 CHECK_TYPELOAD (klass);
10598                                 mono_class_init (klass);
10599                         }
10600                         else
10601                                 klass = array_access_to_klass (*ip);
10602
10603                         if (sp [0]->type != STACK_OBJ)
10604                                 UNVERIFIED;
10605
10606                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10607
10608                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10609                                 // FIXME-VT: OP_ICONST optimization
10610                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10611                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10612                                 ins->opcode = OP_LOADV_MEMBASE;
10613                         } else if (sp [1]->opcode == OP_ICONST) {
10614                                 int array_reg = sp [0]->dreg;
10615                                 int index_reg = sp [1]->dreg;
10616                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10617
10618                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10619                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10620                         } else {
10621                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10622                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10623                         }
10624                         *sp++ = ins;
10625                         if (*ip == CEE_LDELEM)
10626                                 ip += 5;
10627                         else
10628                                 ++ip;
10629                         break;
10630                 }
10631                 case CEE_STELEM_I:
10632                 case CEE_STELEM_I1:
10633                 case CEE_STELEM_I2:
10634                 case CEE_STELEM_I4:
10635                 case CEE_STELEM_I8:
10636                 case CEE_STELEM_R4:
10637                 case CEE_STELEM_R8:
10638                 case CEE_STELEM_REF:
10639                 case CEE_STELEM: {
10640                         CHECK_STACK (3);
10641                         sp -= 3;
10642
10643                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10644
10645                         if (*ip == CEE_STELEM) {
10646                                 CHECK_OPSIZE (5);
10647                                 token = read32 (ip + 1);
10648                                 klass = mini_get_class (method, token, generic_context);
10649                                 CHECK_TYPELOAD (klass);
10650                                 mono_class_init (klass);
10651                         }
10652                         else
10653                                 klass = array_access_to_klass (*ip);
10654
10655                         if (sp [0]->type != STACK_OBJ)
10656                                 UNVERIFIED;
10657
10658                         emit_array_store (cfg, klass, sp, TRUE);
10659
10660                         if (*ip == CEE_STELEM)
10661                                 ip += 5;
10662                         else
10663                                 ++ip;
10664                         inline_costs += 1;
10665                         break;
10666                 }
10667                 case CEE_CKFINITE: {
10668                         CHECK_STACK (1);
10669                         --sp;
10670
10671                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10672                         ins->sreg1 = sp [0]->dreg;
10673                         ins->dreg = alloc_freg (cfg);
10674                         ins->type = STACK_R8;
10675                         MONO_ADD_INS (bblock, ins);
10676
10677                         *sp++ = mono_decompose_opcode (cfg, ins);
10678
10679                         ++ip;
10680                         break;
10681                 }
10682                 case CEE_REFANYVAL: {
10683                         MonoInst *src_var, *src;
10684
10685                         int klass_reg = alloc_preg (cfg);
10686                         int dreg = alloc_preg (cfg);
10687
10688                         GSHAREDVT_FAILURE (*ip);
10689
10690                         CHECK_STACK (1);
10691                         MONO_INST_NEW (cfg, ins, *ip);
10692                         --sp;
10693                         CHECK_OPSIZE (5);
10694                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10695                         CHECK_TYPELOAD (klass);
10696                         mono_class_init (klass);
10697
10698                         context_used = mini_class_check_context_used (cfg, klass);
10699
10700                         // FIXME:
10701                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10702                         if (!src_var)
10703                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10704                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10705                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10706
10707                         if (context_used) {
10708                                 MonoInst *klass_ins;
10709
10710                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10711                                                 klass, MONO_RGCTX_INFO_KLASS);
10712
10713                                 // FIXME:
10714                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10715                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10716                         } else {
10717                                 mini_emit_class_check (cfg, klass_reg, klass);
10718                         }
10719                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10720                         ins->type = STACK_MP;
10721                         *sp++ = ins;
10722                         ip += 5;
10723                         break;
10724                 }
10725                 case CEE_MKREFANY: {
10726                         MonoInst *loc, *addr;
10727
10728                         GSHAREDVT_FAILURE (*ip);
10729
10730                         CHECK_STACK (1);
10731                         MONO_INST_NEW (cfg, ins, *ip);
10732                         --sp;
10733                         CHECK_OPSIZE (5);
10734                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10735                         CHECK_TYPELOAD (klass);
10736                         mono_class_init (klass);
10737
10738                         context_used = mini_class_check_context_used (cfg, klass);
10739
10740                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10741                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10742
10743                         if (context_used) {
10744                                 MonoInst *const_ins;
10745                                 int type_reg = alloc_preg (cfg);
10746
10747                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10748                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10749                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10750                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10751                         } else if (cfg->compile_aot) {
10752                                 int const_reg = alloc_preg (cfg);
10753                                 int type_reg = alloc_preg (cfg);
10754
10755                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10756                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10757                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10758                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10759                         } else {
10760                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10761                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10762                         }
10763                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10764
10765                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10766                         ins->type = STACK_VTYPE;
10767                         ins->klass = mono_defaults.typed_reference_class;
10768                         *sp++ = ins;
10769                         ip += 5;
10770                         break;
10771                 }
10772                 case CEE_LDTOKEN: {
10773                         gpointer handle;
10774                         MonoClass *handle_class;
10775
10776                         CHECK_STACK_OVF (1);
10777
10778                         CHECK_OPSIZE (5);
10779                         n = read32 (ip + 1);
10780
10781                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10782                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10783                                 handle = mono_method_get_wrapper_data (method, n);
10784                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10785                                 if (handle_class == mono_defaults.typehandle_class)
10786                                         handle = &((MonoClass*)handle)->byval_arg;
10787                         }
10788                         else {
10789                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10790                         }
10791                         if (!handle)
10792                                 LOAD_ERROR;
10793                         mono_class_init (handle_class);
10794                         if (cfg->generic_sharing_context) {
10795                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10796                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10797                                         /* This case handles ldtoken
10798                                            of an open type, like for
10799                                            typeof(Gen<>). */
10800                                         context_used = 0;
10801                                 } else if (handle_class == mono_defaults.typehandle_class) {
10802                                         /* If we get a MONO_TYPE_CLASS
10803                                            then we need to provide the
10804                                            open type, not an
10805                                            instantiation of it. */
10806                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10807                                                 context_used = 0;
10808                                         else
10809                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10810                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10811                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10812                                 else if (handle_class == mono_defaults.methodhandle_class)
10813                                         context_used = mini_method_check_context_used (cfg, handle);
10814                                 else
10815                                         g_assert_not_reached ();
10816                         }
10817
10818                         if ((cfg->opt & MONO_OPT_SHARED) &&
10819                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10820                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10821                                 MonoInst *addr, *vtvar, *iargs [3];
10822                                 int method_context_used;
10823
10824                                 method_context_used = mini_method_check_context_used (cfg, method);
10825
10826                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10827
10828                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10829                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10830                                 if (method_context_used) {
10831                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10832                                                 method, MONO_RGCTX_INFO_METHOD);
10833                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10834                                 } else {
10835                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10836                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10837                                 }
10838                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10839
10840                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10841
10842                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10843                         } else {
10844                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10845                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10846                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10847                                         (cmethod->klass == mono_defaults.systemtype_class) &&
10848                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10849                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10850
10851                                         mono_class_init (tclass);
10852                                         if (context_used) {
10853                                                 ins = emit_get_rgctx_klass (cfg, context_used,
10854                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
10855                                         } else if (cfg->compile_aot) {
10856                                                 if (method->wrapper_type) {
10857                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
10858                                                                 /* Special case for static synchronized wrappers */
10859                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
10860                                                         } else {
10861                                                                 /* FIXME: n is not a normal token */
10862                                                                 DISABLE_AOT (cfg);
10863                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
10864                                                         }
10865                                                 } else {
10866                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
10867                                                 }
10868                                         } else {
10869                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
10870                                         }
10871                                         ins->type = STACK_OBJ;
10872                                         ins->klass = cmethod->klass;
10873                                         ip += 5;
10874                                 } else {
10875                                         MonoInst *addr, *vtvar;
10876
10877                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
10878
10879                                         if (context_used) {
10880                                                 if (handle_class == mono_defaults.typehandle_class) {
10881                                                         ins = emit_get_rgctx_klass (cfg, context_used,
10882                                                                         mono_class_from_mono_type (handle),
10883                                                                         MONO_RGCTX_INFO_TYPE);
10884                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
10885                                                         ins = emit_get_rgctx_method (cfg, context_used,
10886                                                                         handle, MONO_RGCTX_INFO_METHOD);
10887                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
10888                                                         ins = emit_get_rgctx_field (cfg, context_used,
10889                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
10890                                                 } else {
10891                                                         g_assert_not_reached ();
10892                                                 }
10893                                         } else if (cfg->compile_aot) {
10894                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
10895                                         } else {
10896                                                 EMIT_NEW_PCONST (cfg, ins, handle);
10897                                         }
10898                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10899                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10900                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10901                                 }
10902                         }
10903
10904                         *sp++ = ins;
10905                         ip += 5;
10906                         break;
10907                 }
10908                 case CEE_THROW:
10909                         CHECK_STACK (1);
10910                         MONO_INST_NEW (cfg, ins, OP_THROW);
10911                         --sp;
10912                         ins->sreg1 = sp [0]->dreg;
10913                         ip++;
10914                         bblock->out_of_line = TRUE;
10915                         MONO_ADD_INS (bblock, ins);
10916                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10917                         MONO_ADD_INS (bblock, ins);
10918                         sp = stack_start;
10919                         
10920                         link_bblock (cfg, bblock, end_bblock);
10921                         start_new_bblock = 1;
10922                         break;
10923                 case CEE_ENDFINALLY:
10924                         /* mono_save_seq_point_info () depends on this */
10925                         if (sp != stack_start)
10926                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
10927                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
10928                         MONO_ADD_INS (bblock, ins);
10929                         ip++;
10930                         start_new_bblock = 1;
10931
10932                         /*
10933                          * Control will leave the method so empty the stack, otherwise
10934                          * the next basic block will start with a nonempty stack.
10935                          */
10936                         while (sp != stack_start) {
10937                                 sp--;
10938                         }
10939                         break;
10940                 case CEE_LEAVE:
10941                 case CEE_LEAVE_S: {
10942                         GList *handlers;
10943
10944                         if (*ip == CEE_LEAVE) {
10945                                 CHECK_OPSIZE (5);
10946                                 target = ip + 5 + (gint32)read32(ip + 1);
10947                         } else {
10948                                 CHECK_OPSIZE (2);
10949                                 target = ip + 2 + (signed char)(ip [1]);
10950                         }
10951
10952                         /* empty the stack */
10953                         while (sp != stack_start) {
10954                                 sp--;
10955                         }
10956
10957                         /* 
10958                          * If this leave statement is in a catch block, check for a
10959                          * pending exception, and rethrow it if necessary.
10960                          * We avoid doing this in runtime invoke wrappers, since those are called
10961                          * by native code which excepts the wrapper to catch all exceptions.
10962                          */
10963                         for (i = 0; i < header->num_clauses; ++i) {
10964                                 MonoExceptionClause *clause = &header->clauses [i];
10965
10966                                 /* 
10967                                  * Use <= in the final comparison to handle clauses with multiple
10968                                  * leave statements, like in bug #78024.
10969                                  * The ordering of the exception clauses guarantees that we find the
10970                                  * innermost clause.
10971                                  */
10972                                 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) {
10973                                         MonoInst *exc_ins;
10974                                         MonoBasicBlock *dont_throw;
10975
10976                                         /*
10977                                           MonoInst *load;
10978
10979                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
10980                                         */
10981
10982                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
10983
10984                                         NEW_BBLOCK (cfg, dont_throw);
10985
10986                                         /*
10987                                          * Currently, we always rethrow the abort exception, despite the 
10988                                          * fact that this is not correct. See thread6.cs for an example. 
10989                                          * But propagating the abort exception is more important than 
10990                                          * getting the sematics right.
10991                                          */
10992                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
10993                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
10994                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
10995
10996                                         MONO_START_BB (cfg, dont_throw);
10997                                         bblock = cfg->cbb;
10998                                 }
10999                         }
11000
11001                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11002                                 GList *tmp;
11003                                 MonoExceptionClause *clause;
11004
11005                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11006                                         clause = tmp->data;
11007                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11008                                         g_assert (tblock);
11009                                         link_bblock (cfg, bblock, tblock);
11010                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11011                                         ins->inst_target_bb = tblock;
11012                                         ins->inst_eh_block = clause;
11013                                         MONO_ADD_INS (bblock, ins);
11014                                         bblock->has_call_handler = 1;
11015                                         if (COMPILE_LLVM (cfg)) {
11016                                                 MonoBasicBlock *target_bb;
11017
11018                                                 /* 
11019                                                  * Link the finally bblock with the target, since it will
11020                                                  * conceptually branch there.
11021                                                  * FIXME: Have to link the bblock containing the endfinally.
11022                                                  */
11023                                                 GET_BBLOCK (cfg, target_bb, target);
11024                                                 link_bblock (cfg, tblock, target_bb);
11025                                         }
11026                                 }
11027                                 g_list_free (handlers);
11028                         } 
11029
11030                         MONO_INST_NEW (cfg, ins, OP_BR);
11031                         MONO_ADD_INS (bblock, ins);
11032                         GET_BBLOCK (cfg, tblock, target);
11033                         link_bblock (cfg, bblock, tblock);
11034                         ins->inst_target_bb = tblock;
11035                         start_new_bblock = 1;
11036
11037                         if (*ip == CEE_LEAVE)
11038                                 ip += 5;
11039                         else
11040                                 ip += 2;
11041
11042                         break;
11043                 }
11044
11045                         /*
11046                          * Mono specific opcodes
11047                          */
11048                 case MONO_CUSTOM_PREFIX: {
11049
11050                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11051
11052                         CHECK_OPSIZE (2);
11053                         switch (ip [1]) {
11054                         case CEE_MONO_ICALL: {
11055                                 gpointer func;
11056                                 MonoJitICallInfo *info;
11057
11058                                 token = read32 (ip + 2);
11059                                 func = mono_method_get_wrapper_data (method, token);
11060                                 info = mono_find_jit_icall_by_addr (func);
11061                                 if (!info)
11062                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11063                                 g_assert (info);
11064
11065                                 CHECK_STACK (info->sig->param_count);
11066                                 sp -= info->sig->param_count;
11067
11068                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11069                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11070                                         *sp++ = ins;
11071
11072                                 ip += 6;
11073                                 inline_costs += 10 * num_calls++;
11074
11075                                 break;
11076                         }
11077                         case CEE_MONO_LDPTR: {
11078                                 gpointer ptr;
11079
11080                                 CHECK_STACK_OVF (1);
11081                                 CHECK_OPSIZE (6);
11082                                 token = read32 (ip + 2);
11083
11084                                 ptr = mono_method_get_wrapper_data (method, token);
11085                                 /* FIXME: Generalize this */
11086                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11087                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11088                                         *sp++ = ins;
11089                                         ip += 6;
11090                                         break;
11091                                 }
11092                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11093                                 *sp++ = ins;
11094                                 ip += 6;
11095                                 inline_costs += 10 * num_calls++;
11096                                 /* Can't embed random pointers into AOT code */
11097                                 DISABLE_AOT (cfg);
11098                                 break;
11099                         }
11100                         case CEE_MONO_JIT_ICALL_ADDR: {
11101                                 MonoJitICallInfo *callinfo;
11102                                 gpointer ptr;
11103
11104                                 CHECK_STACK_OVF (1);
11105                                 CHECK_OPSIZE (6);
11106                                 token = read32 (ip + 2);
11107
11108                                 ptr = mono_method_get_wrapper_data (method, token);
11109                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11110                                 g_assert (callinfo);
11111                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11112                                 *sp++ = ins;
11113                                 ip += 6;
11114                                 inline_costs += 10 * num_calls++;
11115                                 break;
11116                         }
11117                         case CEE_MONO_ICALL_ADDR: {
11118                                 MonoMethod *cmethod;
11119                                 gpointer ptr;
11120
11121                                 CHECK_STACK_OVF (1);
11122                                 CHECK_OPSIZE (6);
11123                                 token = read32 (ip + 2);
11124
11125                                 cmethod = mono_method_get_wrapper_data (method, token);
11126
11127                                 if (cfg->compile_aot) {
11128                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11129                                 } else {
11130                                         ptr = mono_lookup_internal_call (cmethod);
11131                                         g_assert (ptr);
11132                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11133                                 }
11134                                 *sp++ = ins;
11135                                 ip += 6;
11136                                 break;
11137                         }
11138                         case CEE_MONO_VTADDR: {
11139                                 MonoInst *src_var, *src;
11140
11141                                 CHECK_STACK (1);
11142                                 --sp;
11143
11144                                 // FIXME:
11145                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11146                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11147                                 *sp++ = src;
11148                                 ip += 2;
11149                                 break;
11150                         }
11151                         case CEE_MONO_NEWOBJ: {
11152                                 MonoInst *iargs [2];
11153
11154                                 CHECK_STACK_OVF (1);
11155                                 CHECK_OPSIZE (6);
11156                                 token = read32 (ip + 2);
11157                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11158                                 mono_class_init (klass);
11159                                 NEW_DOMAINCONST (cfg, iargs [0]);
11160                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11161                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11162                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11163                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11164                                 ip += 6;
11165                                 inline_costs += 10 * num_calls++;
11166                                 break;
11167                         }
11168                         case CEE_MONO_OBJADDR:
11169                                 CHECK_STACK (1);
11170                                 --sp;
11171                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11172                                 ins->dreg = alloc_ireg_mp (cfg);
11173                                 ins->sreg1 = sp [0]->dreg;
11174                                 ins->type = STACK_MP;
11175                                 MONO_ADD_INS (cfg->cbb, ins);
11176                                 *sp++ = ins;
11177                                 ip += 2;
11178                                 break;
11179                         case CEE_MONO_LDNATIVEOBJ:
11180                                 /*
11181                                  * Similar to LDOBJ, but instead load the unmanaged 
11182                                  * representation of the vtype to the stack.
11183                                  */
11184                                 CHECK_STACK (1);
11185                                 CHECK_OPSIZE (6);
11186                                 --sp;
11187                                 token = read32 (ip + 2);
11188                                 klass = mono_method_get_wrapper_data (method, token);
11189                                 g_assert (klass->valuetype);
11190                                 mono_class_init (klass);
11191
11192                                 {
11193                                         MonoInst *src, *dest, *temp;
11194
11195                                         src = sp [0];
11196                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11197                                         temp->backend.is_pinvoke = 1;
11198                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11199                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11200
11201                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11202                                         dest->type = STACK_VTYPE;
11203                                         dest->klass = klass;
11204
11205                                         *sp ++ = dest;
11206                                         ip += 6;
11207                                 }
11208                                 break;
11209                         case CEE_MONO_RETOBJ: {
11210                                 /*
11211                                  * Same as RET, but return the native representation of a vtype
11212                                  * to the caller.
11213                                  */
11214                                 g_assert (cfg->ret);
11215                                 g_assert (mono_method_signature (method)->pinvoke); 
11216                                 CHECK_STACK (1);
11217                                 --sp;
11218                                 
11219                                 CHECK_OPSIZE (6);
11220                                 token = read32 (ip + 2);    
11221                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11222
11223                                 if (!cfg->vret_addr) {
11224                                         g_assert (cfg->ret_var_is_local);
11225
11226                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11227                                 } else {
11228                                         EMIT_NEW_RETLOADA (cfg, ins);
11229                                 }
11230                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11231                                 
11232                                 if (sp != stack_start)
11233                                         UNVERIFIED;
11234                                 
11235                                 MONO_INST_NEW (cfg, ins, OP_BR);
11236                                 ins->inst_target_bb = end_bblock;
11237                                 MONO_ADD_INS (bblock, ins);
11238                                 link_bblock (cfg, bblock, end_bblock);
11239                                 start_new_bblock = 1;
11240                                 ip += 6;
11241                                 break;
11242                         }
11243                         case CEE_MONO_CISINST:
11244                         case CEE_MONO_CCASTCLASS: {
11245                                 int token;
11246                                 CHECK_STACK (1);
11247                                 --sp;
11248                                 CHECK_OPSIZE (6);
11249                                 token = read32 (ip + 2);
11250                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11251                                 if (ip [1] == CEE_MONO_CISINST)
11252                                         ins = handle_cisinst (cfg, klass, sp [0]);
11253                                 else
11254                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11255                                 bblock = cfg->cbb;
11256                                 *sp++ = ins;
11257                                 ip += 6;
11258                                 break;
11259                         }
11260                         case CEE_MONO_SAVE_LMF:
11261                         case CEE_MONO_RESTORE_LMF:
11262 #ifdef MONO_ARCH_HAVE_LMF_OPS
11263                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11264                                 MONO_ADD_INS (bblock, ins);
11265                                 cfg->need_lmf_area = TRUE;
11266 #endif
11267                                 ip += 2;
11268                                 break;
11269                         case CEE_MONO_CLASSCONST:
11270                                 CHECK_STACK_OVF (1);
11271                                 CHECK_OPSIZE (6);
11272                                 token = read32 (ip + 2);
11273                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11274                                 *sp++ = ins;
11275                                 ip += 6;
11276                                 inline_costs += 10 * num_calls++;
11277                                 break;
11278                         case CEE_MONO_NOT_TAKEN:
11279                                 bblock->out_of_line = TRUE;
11280                                 ip += 2;
11281                                 break;
11282                         case CEE_MONO_TLS: {
11283                                 int key;
11284
11285                                 CHECK_STACK_OVF (1);
11286                                 CHECK_OPSIZE (6);
11287                                 key = (gint32)read32 (ip + 2);
11288                                 g_assert (key < TLS_KEY_NUM);
11289
11290                                 ins = mono_create_tls_get (cfg, key);
11291                                 if (!ins) {
11292                                         if (cfg->compile_aot) {
11293                                                 DISABLE_AOT (cfg);
11294                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11295                                                 ins->dreg = alloc_preg (cfg);
11296                                                 ins->type = STACK_PTR;
11297                                         } else {
11298                                                 g_assert_not_reached ();
11299                                         }
11300                                 }
11301                                 ins->type = STACK_PTR;
11302                                 MONO_ADD_INS (bblock, ins);
11303                                 *sp++ = ins;
11304                                 ip += 6;
11305                                 break;
11306                         }
11307                         case CEE_MONO_DYN_CALL: {
11308                                 MonoCallInst *call;
11309
11310                                 /* It would be easier to call a trampoline, but that would put an
11311                                  * extra frame on the stack, confusing exception handling. So
11312                                  * implement it inline using an opcode for now.
11313                                  */
11314
11315                                 if (!cfg->dyn_call_var) {
11316                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11317                                         /* prevent it from being register allocated */
11318                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11319                                 }
11320
11321                                 /* Has to use a call inst since it local regalloc expects it */
11322                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11323                                 ins = (MonoInst*)call;
11324                                 sp -= 2;
11325                                 ins->sreg1 = sp [0]->dreg;
11326                                 ins->sreg2 = sp [1]->dreg;
11327                                 MONO_ADD_INS (bblock, ins);
11328
11329                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11330
11331                                 ip += 2;
11332                                 inline_costs += 10 * num_calls++;
11333
11334                                 break;
11335                         }
11336                         case CEE_MONO_MEMORY_BARRIER: {
11337                                 CHECK_OPSIZE (5);
11338                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11339                                 ip += 5;
11340                                 break;
11341                         }
11342                         case CEE_MONO_JIT_ATTACH: {
11343                                 MonoInst *args [16];
11344                                 MonoInst *ad_ins, *lmf_ins;
11345                                 MonoBasicBlock *next_bb = NULL;
11346
11347                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11348
11349                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11350                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11351
11352 #if TARGET_WIN32
11353                                 ad_ins = NULL;
11354                                 lmf_ins = NULL;
11355 #else
11356                                 ad_ins = mono_get_domain_intrinsic (cfg);
11357                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11358 #endif
11359
11360                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11361                                         NEW_BBLOCK (cfg, next_bb);
11362
11363                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11364                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11365                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11366
11367                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11368                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11369                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11370                                 }
11371
11372                                 if (cfg->compile_aot) {
11373                                         /* AOT code is only used in the root domain */
11374                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11375                                 } else {
11376                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11377                                 }
11378                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11379                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11380
11381                                 if (next_bb) {
11382                                         MONO_START_BB (cfg, next_bb);
11383                                         bblock = cfg->cbb;
11384                                 }
11385                                 ip += 2;
11386                                 break;
11387                         }
11388                         case CEE_MONO_JIT_DETACH: {
11389                                 MonoInst *args [16];
11390
11391                                 /* Restore the original domain */
11392                                 dreg = alloc_ireg (cfg);
11393                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11394                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11395                                 ip += 2;
11396                                 break;
11397                         }
11398                         default:
11399                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11400                                 break;
11401                         }
11402                         break;
11403                 }
11404
11405                 case CEE_PREFIX1: {
11406                         CHECK_OPSIZE (2);
11407                         switch (ip [1]) {
11408                         case CEE_ARGLIST: {
11409                                 /* somewhat similar to LDTOKEN */
11410                                 MonoInst *addr, *vtvar;
11411                                 CHECK_STACK_OVF (1);
11412                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11413
11414                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11415                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11416
11417                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11418                                 ins->type = STACK_VTYPE;
11419                                 ins->klass = mono_defaults.argumenthandle_class;
11420                                 *sp++ = ins;
11421                                 ip += 2;
11422                                 break;
11423                         }
11424                         case CEE_CEQ:
11425                         case CEE_CGT:
11426                         case CEE_CGT_UN:
11427                         case CEE_CLT:
11428                         case CEE_CLT_UN: {
11429                                 MonoInst *cmp;
11430                                 CHECK_STACK (2);
11431                                 /*
11432                                  * The following transforms:
11433                                  *    CEE_CEQ    into OP_CEQ
11434                                  *    CEE_CGT    into OP_CGT
11435                                  *    CEE_CGT_UN into OP_CGT_UN
11436                                  *    CEE_CLT    into OP_CLT
11437                                  *    CEE_CLT_UN into OP_CLT_UN
11438                                  */
11439                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11440                                 
11441                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11442                                 sp -= 2;
11443                                 cmp->sreg1 = sp [0]->dreg;
11444                                 cmp->sreg2 = sp [1]->dreg;
11445                                 type_from_op (cmp, sp [0], sp [1]);
11446                                 CHECK_TYPE (cmp);
11447                                 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))))
11448                                         cmp->opcode = OP_LCOMPARE;
11449                                 else if (sp [0]->type == STACK_R8)
11450                                         cmp->opcode = OP_FCOMPARE;
11451                                 else
11452                                         cmp->opcode = OP_ICOMPARE;
11453                                 MONO_ADD_INS (bblock, cmp);
11454                                 ins->type = STACK_I4;
11455                                 ins->dreg = alloc_dreg (cfg, ins->type);
11456                                 type_from_op (ins, sp [0], sp [1]);
11457
11458                                 if (cmp->opcode == OP_FCOMPARE) {
11459                                         /*
11460                                          * The backends expect the fceq opcodes to do the
11461                                          * comparison too.
11462                                          */
11463                                         cmp->opcode = OP_NOP;
11464                                         ins->sreg1 = cmp->sreg1;
11465                                         ins->sreg2 = cmp->sreg2;
11466                                 }
11467                                 MONO_ADD_INS (bblock, ins);
11468                                 *sp++ = ins;
11469                                 ip += 2;
11470                                 break;
11471                         }
11472                         case CEE_LDFTN: {
11473                                 MonoInst *argconst;
11474                                 MonoMethod *cil_method;
11475
11476                                 CHECK_STACK_OVF (1);
11477                                 CHECK_OPSIZE (6);
11478                                 n = read32 (ip + 2);
11479                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11480                                 if (!cmethod || mono_loader_get_last_error ())
11481                                         LOAD_ERROR;
11482                                 mono_class_init (cmethod->klass);
11483
11484                                 mono_save_token_info (cfg, image, n, cmethod);
11485
11486                                 context_used = mini_method_check_context_used (cfg, cmethod);
11487
11488                                 cil_method = cmethod;
11489                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11490                                         METHOD_ACCESS_FAILURE;
11491
11492                                 if (mono_security_cas_enabled ()) {
11493                                         if (check_linkdemand (cfg, method, cmethod))
11494                                                 INLINE_FAILURE ("linkdemand");
11495                                         CHECK_CFG_EXCEPTION;
11496                                 } else if (mono_security_core_clr_enabled ()) {
11497                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11498                                 }
11499
11500                                 /* 
11501                                  * Optimize the common case of ldftn+delegate creation
11502                                  */
11503                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11504                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11505                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11506                                                 MonoInst *target_ins;
11507                                                 MonoMethod *invoke;
11508                                                 int invoke_context_used;
11509
11510                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11511                                                 if (!invoke || !mono_method_signature (invoke))
11512                                                         LOAD_ERROR;
11513
11514                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11515
11516                                                 target_ins = sp [-1];
11517
11518                                                 if (mono_security_core_clr_enabled ())
11519                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11520
11521                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11522                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11523                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11524                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11525                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11526                                                         }
11527                                                 }
11528
11529 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11530                                                 /* FIXME: SGEN support */
11531                                                 if (invoke_context_used == 0) {
11532                                                         ip += 6;
11533                                                         if (cfg->verbose_level > 3)
11534                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11535                                                         sp --;
11536                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11537                                                         CHECK_CFG_EXCEPTION;
11538                                                         ip += 5;                        
11539                                                         sp ++;
11540                                                         break;
11541                                                 }
11542 #endif
11543                                         }
11544                                 }
11545
11546                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11547                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11548                                 *sp++ = ins;
11549                                 
11550                                 ip += 6;
11551                                 inline_costs += 10 * num_calls++;
11552                                 break;
11553                         }
11554                         case CEE_LDVIRTFTN: {
11555                                 MonoInst *args [2];
11556
11557                                 CHECK_STACK (1);
11558                                 CHECK_OPSIZE (6);
11559                                 n = read32 (ip + 2);
11560                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11561                                 if (!cmethod || mono_loader_get_last_error ())
11562                                         LOAD_ERROR;
11563                                 mono_class_init (cmethod->klass);
11564  
11565                                 context_used = mini_method_check_context_used (cfg, cmethod);
11566
11567                                 if (mono_security_cas_enabled ()) {
11568                                         if (check_linkdemand (cfg, method, cmethod))
11569                                                 INLINE_FAILURE ("linkdemand");
11570                                         CHECK_CFG_EXCEPTION;
11571                                 } else if (mono_security_core_clr_enabled ()) {
11572                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11573                                 }
11574
11575                                 --sp;
11576                                 args [0] = *sp;
11577
11578                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11579                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11580
11581                                 if (context_used)
11582                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11583                                 else
11584                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11585
11586                                 ip += 6;
11587                                 inline_costs += 10 * num_calls++;
11588                                 break;
11589                         }
11590                         case CEE_LDARG:
11591                                 CHECK_STACK_OVF (1);
11592                                 CHECK_OPSIZE (4);
11593                                 n = read16 (ip + 2);
11594                                 CHECK_ARG (n);
11595                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11596                                 *sp++ = ins;
11597                                 ip += 4;
11598                                 break;
11599                         case CEE_LDARGA:
11600                                 CHECK_STACK_OVF (1);
11601                                 CHECK_OPSIZE (4);
11602                                 n = read16 (ip + 2);
11603                                 CHECK_ARG (n);
11604                                 NEW_ARGLOADA (cfg, ins, n);
11605                                 MONO_ADD_INS (cfg->cbb, ins);
11606                                 *sp++ = ins;
11607                                 ip += 4;
11608                                 break;
11609                         case CEE_STARG:
11610                                 CHECK_STACK (1);
11611                                 --sp;
11612                                 CHECK_OPSIZE (4);
11613                                 n = read16 (ip + 2);
11614                                 CHECK_ARG (n);
11615                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11616                                         UNVERIFIED;
11617                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11618                                 ip += 4;
11619                                 break;
11620                         case CEE_LDLOC:
11621                                 CHECK_STACK_OVF (1);
11622                                 CHECK_OPSIZE (4);
11623                                 n = read16 (ip + 2);
11624                                 CHECK_LOCAL (n);
11625                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11626                                 *sp++ = ins;
11627                                 ip += 4;
11628                                 break;
11629                         case CEE_LDLOCA: {
11630                                 unsigned char *tmp_ip;
11631                                 CHECK_STACK_OVF (1);
11632                                 CHECK_OPSIZE (4);
11633                                 n = read16 (ip + 2);
11634                                 CHECK_LOCAL (n);
11635
11636                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11637                                         ip = tmp_ip;
11638                                         inline_costs += 1;
11639                                         break;
11640                                 }                       
11641                                 
11642                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11643                                 *sp++ = ins;
11644                                 ip += 4;
11645                                 break;
11646                         }
11647                         case CEE_STLOC:
11648                                 CHECK_STACK (1);
11649                                 --sp;
11650                                 CHECK_OPSIZE (4);
11651                                 n = read16 (ip + 2);
11652                                 CHECK_LOCAL (n);
11653                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11654                                         UNVERIFIED;
11655                                 emit_stloc_ir (cfg, sp, header, n);
11656                                 ip += 4;
11657                                 inline_costs += 1;
11658                                 break;
11659                         case CEE_LOCALLOC:
11660                                 CHECK_STACK (1);
11661                                 --sp;
11662                                 if (sp != stack_start) 
11663                                         UNVERIFIED;
11664                                 if (cfg->method != method) 
11665                                         /* 
11666                                          * Inlining this into a loop in a parent could lead to 
11667                                          * stack overflows which is different behavior than the
11668                                          * non-inlined case, thus disable inlining in this case.
11669                                          */
11670                                         goto inline_failure;
11671
11672                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11673                                 ins->dreg = alloc_preg (cfg);
11674                                 ins->sreg1 = sp [0]->dreg;
11675                                 ins->type = STACK_PTR;
11676                                 MONO_ADD_INS (cfg->cbb, ins);
11677
11678                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11679                                 if (init_locals)
11680                                         ins->flags |= MONO_INST_INIT;
11681
11682                                 *sp++ = ins;
11683                                 ip += 2;
11684                                 break;
11685                         case CEE_ENDFILTER: {
11686                                 MonoExceptionClause *clause, *nearest;
11687                                 int cc, nearest_num;
11688
11689                                 CHECK_STACK (1);
11690                                 --sp;
11691                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11692                                         UNVERIFIED;
11693                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11694                                 ins->sreg1 = (*sp)->dreg;
11695                                 MONO_ADD_INS (bblock, ins);
11696                                 start_new_bblock = 1;
11697                                 ip += 2;
11698
11699                                 nearest = NULL;
11700                                 nearest_num = 0;
11701                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11702                                         clause = &header->clauses [cc];
11703                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11704                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11705                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11706                                                 nearest = clause;
11707                                                 nearest_num = cc;
11708                                         }
11709                                 }
11710                                 g_assert (nearest);
11711                                 if ((ip - header->code) != nearest->handler_offset)
11712                                         UNVERIFIED;
11713
11714                                 break;
11715                         }
11716                         case CEE_UNALIGNED_:
11717                                 ins_flag |= MONO_INST_UNALIGNED;
11718                                 /* FIXME: record alignment? we can assume 1 for now */
11719                                 CHECK_OPSIZE (3);
11720                                 ip += 3;
11721                                 break;
11722                         case CEE_VOLATILE_:
11723                                 ins_flag |= MONO_INST_VOLATILE;
11724                                 ip += 2;
11725                                 break;
11726                         case CEE_TAIL_:
11727                                 ins_flag   |= MONO_INST_TAILCALL;
11728                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11729                                 /* Can't inline tail calls at this time */
11730                                 inline_costs += 100000;
11731                                 ip += 2;
11732                                 break;
11733                         case CEE_INITOBJ:
11734                                 CHECK_STACK (1);
11735                                 --sp;
11736                                 CHECK_OPSIZE (6);
11737                                 token = read32 (ip + 2);
11738                                 klass = mini_get_class (method, token, generic_context);
11739                                 CHECK_TYPELOAD (klass);
11740                                 if (generic_class_is_reference_type (cfg, klass))
11741                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11742                                 else
11743                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11744                                 ip += 6;
11745                                 inline_costs += 1;
11746                                 break;
11747                         case CEE_CONSTRAINED_:
11748                                 CHECK_OPSIZE (6);
11749                                 token = read32 (ip + 2);
11750                                 constrained_call = mini_get_class (method, token, generic_context);
11751                                 CHECK_TYPELOAD (constrained_call);
11752                                 ip += 6;
11753                                 break;
11754                         case CEE_CPBLK:
11755                         case CEE_INITBLK: {
11756                                 MonoInst *iargs [3];
11757                                 CHECK_STACK (3);
11758                                 sp -= 3;
11759
11760                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11761                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11762                                 } else if ((ip [1] == CEE_INITBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
11763                                         /* emit_memset only works when val == 0 */
11764                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11765                                 } else {
11766                                         iargs [0] = sp [0];
11767                                         iargs [1] = sp [1];
11768                                         iargs [2] = sp [2];
11769                                         if (ip [1] == CEE_CPBLK) {
11770                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11771                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11772                                         } else {
11773                                                 MonoMethod *memset_method = get_memset_method ();
11774                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11775                                         }
11776                                 }
11777                                 ip += 2;
11778                                 inline_costs += 1;
11779                                 break;
11780                         }
11781                         case CEE_NO_:
11782                                 CHECK_OPSIZE (3);
11783                                 if (ip [2] & 0x1)
11784                                         ins_flag |= MONO_INST_NOTYPECHECK;
11785                                 if (ip [2] & 0x2)
11786                                         ins_flag |= MONO_INST_NORANGECHECK;
11787                                 /* we ignore the no-nullcheck for now since we
11788                                  * really do it explicitly only when doing callvirt->call
11789                                  */
11790                                 ip += 3;
11791                                 break;
11792                         case CEE_RETHROW: {
11793                                 MonoInst *load;
11794                                 int handler_offset = -1;
11795
11796                                 for (i = 0; i < header->num_clauses; ++i) {
11797                                         MonoExceptionClause *clause = &header->clauses [i];
11798                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11799                                                 handler_offset = clause->handler_offset;
11800                                                 break;
11801                                         }
11802                                 }
11803
11804                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11805
11806                                 g_assert (handler_offset != -1);
11807
11808                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11809                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11810                                 ins->sreg1 = load->dreg;
11811                                 MONO_ADD_INS (bblock, ins);
11812
11813                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11814                                 MONO_ADD_INS (bblock, ins);
11815
11816                                 sp = stack_start;
11817                                 link_bblock (cfg, bblock, end_bblock);
11818                                 start_new_bblock = 1;
11819                                 ip += 2;
11820                                 break;
11821                         }
11822                         case CEE_SIZEOF: {
11823                                 guint32 val;
11824                                 int ialign;
11825
11826                                 GSHAREDVT_FAILURE (*ip);
11827
11828                                 CHECK_STACK_OVF (1);
11829                                 CHECK_OPSIZE (6);
11830                                 token = read32 (ip + 2);
11831                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11832                                         MonoType *type = mono_type_create_from_typespec (image, token);
11833                                         val = mono_type_size (type, &ialign);
11834                                 } else {
11835                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11836                                         CHECK_TYPELOAD (klass);
11837                                         mono_class_init (klass);
11838                                         val = mono_type_size (&klass->byval_arg, &ialign);
11839                                 }
11840                                 EMIT_NEW_ICONST (cfg, ins, val);
11841                                 *sp++= ins;
11842                                 ip += 6;
11843                                 break;
11844                         }
11845                         case CEE_REFANYTYPE: {
11846                                 MonoInst *src_var, *src;
11847
11848                                 GSHAREDVT_FAILURE (*ip);
11849
11850                                 CHECK_STACK (1);
11851                                 --sp;
11852
11853                                 // FIXME:
11854                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11855                                 if (!src_var)
11856                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11857                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11858                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
11859                                 *sp++ = ins;
11860                                 ip += 2;
11861                                 break;
11862                         }
11863                         case CEE_READONLY_:
11864                                 readonly = TRUE;
11865                                 ip += 2;
11866                                 break;
11867
11868                         case CEE_UNUSED56:
11869                         case CEE_UNUSED57:
11870                         case CEE_UNUSED70:
11871                         case CEE_UNUSED:
11872                         case CEE_UNUSED99:
11873                                 UNVERIFIED;
11874                                 
11875                         default:
11876                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
11877                                 UNVERIFIED;
11878                         }
11879                         break;
11880                 }
11881                 case CEE_UNUSED58:
11882                 case CEE_UNUSED1:
11883                         UNVERIFIED;
11884
11885                 default:
11886                         g_warning ("opcode 0x%02x not handled", *ip);
11887                         UNVERIFIED;
11888                 }
11889         }
11890         if (start_new_bblock != 1)
11891                 UNVERIFIED;
11892
11893         bblock->cil_length = ip - bblock->cil_code;
11894         if (bblock->next_bb) {
11895                 /* This could already be set because of inlining, #693905 */
11896                 MonoBasicBlock *bb = bblock;
11897
11898                 while (bb->next_bb)
11899                         bb = bb->next_bb;
11900                 bb->next_bb = end_bblock;
11901         } else {
11902                 bblock->next_bb = end_bblock;
11903         }
11904
11905         if (cfg->method == method && cfg->domainvar) {
11906                 MonoInst *store;
11907                 MonoInst *get_domain;
11908
11909                 cfg->cbb = init_localsbb;
11910
11911                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
11912                         MONO_ADD_INS (cfg->cbb, get_domain);
11913                 } else {
11914                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
11915                 }
11916                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
11917                 MONO_ADD_INS (cfg->cbb, store);
11918         }
11919
11920 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
11921         if (cfg->compile_aot)
11922                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
11923                 mono_get_got_var (cfg);
11924 #endif
11925
11926         if (cfg->method == method && cfg->got_var)
11927                 mono_emit_load_got_addr (cfg);
11928
11929         if (init_locals) {
11930                 cfg->cbb = init_localsbb;
11931                 cfg->ip = NULL;
11932                 for (i = 0; i < header->num_locals; ++i) {
11933                         emit_init_local (cfg, i, header->locals [i]);
11934                 }
11935         }
11936
11937         if (cfg->init_ref_vars && cfg->method == method) {
11938                 /* Emit initialization for ref vars */
11939                 // FIXME: Avoid duplication initialization for IL locals.
11940                 for (i = 0; i < cfg->num_varinfo; ++i) {
11941                         MonoInst *ins = cfg->varinfo [i];
11942
11943                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
11944                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
11945                 }
11946         }
11947
11948         if (cfg->lmf_var && cfg->method == method) {
11949                 cfg->cbb = init_localsbb;
11950                 emit_push_lmf (cfg);
11951         }
11952
11953         if (seq_points) {
11954                 MonoBasicBlock *bb;
11955
11956                 /*
11957                  * Make seq points at backward branch targets interruptable.
11958                  */
11959                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
11960                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
11961                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
11962         }
11963
11964         /* Add a sequence point for method entry/exit events */
11965         if (seq_points) {
11966                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
11967                 MONO_ADD_INS (init_localsbb, ins);
11968                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
11969                 MONO_ADD_INS (cfg->bb_exit, ins);
11970         }
11971
11972         /*
11973          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
11974          * the code they refer to was dead (#11880).
11975          */
11976         if (sym_seq_points) {
11977                 for (i = 0; i < header->code_size; ++i) {
11978                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
11979                                 MonoInst *ins;
11980
11981                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
11982                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
11983                         }
11984                 }
11985         }
11986
11987         cfg->ip = NULL;
11988
11989         if (cfg->method == method) {
11990                 MonoBasicBlock *bb;
11991                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11992                         bb->region = mono_find_block_region (cfg, bb->real_offset);
11993                         if (cfg->spvars)
11994                                 mono_create_spvar_for_region (cfg, bb->region);
11995                         if (cfg->verbose_level > 2)
11996                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
11997                 }
11998         }
11999
12000         g_slist_free (class_inits);
12001         dont_inline = g_list_remove (dont_inline, method);
12002
12003         if (inline_costs < 0) {
12004                 char *mname;
12005
12006                 /* Method is too large */
12007                 mname = mono_method_full_name (method, TRUE);
12008                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12009                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12010                 g_free (mname);
12011                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12012                 mono_basic_block_free (original_bb);
12013                 return -1;
12014         }
12015
12016         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12017                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12018
12019         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12020         mono_basic_block_free (original_bb);
12021         return inline_costs;
12022  
12023  exception_exit:
12024         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12025         goto cleanup;
12026
12027  inline_failure:
12028         goto cleanup;
12029
12030  load_error:
12031         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
12032         goto cleanup;
12033
12034  unverified:
12035         set_exception_type_from_invalid_il (cfg, method, ip);
12036         goto cleanup;
12037
12038  cleanup:
12039         g_slist_free (class_inits);
12040         mono_basic_block_free (original_bb);
12041         dont_inline = g_list_remove (dont_inline, method);
12042         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12043         return -1;
12044 }
12045
12046 static int
12047 store_membase_reg_to_store_membase_imm (int opcode)
12048 {
12049         switch (opcode) {
12050         case OP_STORE_MEMBASE_REG:
12051                 return OP_STORE_MEMBASE_IMM;
12052         case OP_STOREI1_MEMBASE_REG:
12053                 return OP_STOREI1_MEMBASE_IMM;
12054         case OP_STOREI2_MEMBASE_REG:
12055                 return OP_STOREI2_MEMBASE_IMM;
12056         case OP_STOREI4_MEMBASE_REG:
12057                 return OP_STOREI4_MEMBASE_IMM;
12058         case OP_STOREI8_MEMBASE_REG:
12059                 return OP_STOREI8_MEMBASE_IMM;
12060         default:
12061                 g_assert_not_reached ();
12062         }
12063
12064         return -1;
12065 }               
12066
12067 int
12068 mono_op_to_op_imm (int opcode)
12069 {
12070         switch (opcode) {
12071         case OP_IADD:
12072                 return OP_IADD_IMM;
12073         case OP_ISUB:
12074                 return OP_ISUB_IMM;
12075         case OP_IDIV:
12076                 return OP_IDIV_IMM;
12077         case OP_IDIV_UN:
12078                 return OP_IDIV_UN_IMM;
12079         case OP_IREM:
12080                 return OP_IREM_IMM;
12081         case OP_IREM_UN:
12082                 return OP_IREM_UN_IMM;
12083         case OP_IMUL:
12084                 return OP_IMUL_IMM;
12085         case OP_IAND:
12086                 return OP_IAND_IMM;
12087         case OP_IOR:
12088                 return OP_IOR_IMM;
12089         case OP_IXOR:
12090                 return OP_IXOR_IMM;
12091         case OP_ISHL:
12092                 return OP_ISHL_IMM;
12093         case OP_ISHR:
12094                 return OP_ISHR_IMM;
12095         case OP_ISHR_UN:
12096                 return OP_ISHR_UN_IMM;
12097
12098         case OP_LADD:
12099                 return OP_LADD_IMM;
12100         case OP_LSUB:
12101                 return OP_LSUB_IMM;
12102         case OP_LAND:
12103                 return OP_LAND_IMM;
12104         case OP_LOR:
12105                 return OP_LOR_IMM;
12106         case OP_LXOR:
12107                 return OP_LXOR_IMM;
12108         case OP_LSHL:
12109                 return OP_LSHL_IMM;
12110         case OP_LSHR:
12111                 return OP_LSHR_IMM;
12112         case OP_LSHR_UN:
12113                 return OP_LSHR_UN_IMM;          
12114
12115         case OP_COMPARE:
12116                 return OP_COMPARE_IMM;
12117         case OP_ICOMPARE:
12118                 return OP_ICOMPARE_IMM;
12119         case OP_LCOMPARE:
12120                 return OP_LCOMPARE_IMM;
12121
12122         case OP_STORE_MEMBASE_REG:
12123                 return OP_STORE_MEMBASE_IMM;
12124         case OP_STOREI1_MEMBASE_REG:
12125                 return OP_STOREI1_MEMBASE_IMM;
12126         case OP_STOREI2_MEMBASE_REG:
12127                 return OP_STOREI2_MEMBASE_IMM;
12128         case OP_STOREI4_MEMBASE_REG:
12129                 return OP_STOREI4_MEMBASE_IMM;
12130
12131 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12132         case OP_X86_PUSH:
12133                 return OP_X86_PUSH_IMM;
12134         case OP_X86_COMPARE_MEMBASE_REG:
12135                 return OP_X86_COMPARE_MEMBASE_IMM;
12136 #endif
12137 #if defined(TARGET_AMD64)
12138         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12139                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12140 #endif
12141         case OP_VOIDCALL_REG:
12142                 return OP_VOIDCALL;
12143         case OP_CALL_REG:
12144                 return OP_CALL;
12145         case OP_LCALL_REG:
12146                 return OP_LCALL;
12147         case OP_FCALL_REG:
12148                 return OP_FCALL;
12149         case OP_LOCALLOC:
12150                 return OP_LOCALLOC_IMM;
12151         }
12152
12153         return -1;
12154 }
12155
12156 static int
12157 ldind_to_load_membase (int opcode)
12158 {
12159         switch (opcode) {
12160         case CEE_LDIND_I1:
12161                 return OP_LOADI1_MEMBASE;
12162         case CEE_LDIND_U1:
12163                 return OP_LOADU1_MEMBASE;
12164         case CEE_LDIND_I2:
12165                 return OP_LOADI2_MEMBASE;
12166         case CEE_LDIND_U2:
12167                 return OP_LOADU2_MEMBASE;
12168         case CEE_LDIND_I4:
12169                 return OP_LOADI4_MEMBASE;
12170         case CEE_LDIND_U4:
12171                 return OP_LOADU4_MEMBASE;
12172         case CEE_LDIND_I:
12173                 return OP_LOAD_MEMBASE;
12174         case CEE_LDIND_REF:
12175                 return OP_LOAD_MEMBASE;
12176         case CEE_LDIND_I8:
12177                 return OP_LOADI8_MEMBASE;
12178         case CEE_LDIND_R4:
12179                 return OP_LOADR4_MEMBASE;
12180         case CEE_LDIND_R8:
12181                 return OP_LOADR8_MEMBASE;
12182         default:
12183                 g_assert_not_reached ();
12184         }
12185
12186         return -1;
12187 }
12188
12189 static int
12190 stind_to_store_membase (int opcode)
12191 {
12192         switch (opcode) {
12193         case CEE_STIND_I1:
12194                 return OP_STOREI1_MEMBASE_REG;
12195         case CEE_STIND_I2:
12196                 return OP_STOREI2_MEMBASE_REG;
12197         case CEE_STIND_I4:
12198                 return OP_STOREI4_MEMBASE_REG;
12199         case CEE_STIND_I:
12200         case CEE_STIND_REF:
12201                 return OP_STORE_MEMBASE_REG;
12202         case CEE_STIND_I8:
12203                 return OP_STOREI8_MEMBASE_REG;
12204         case CEE_STIND_R4:
12205                 return OP_STORER4_MEMBASE_REG;
12206         case CEE_STIND_R8:
12207                 return OP_STORER8_MEMBASE_REG;
12208         default:
12209                 g_assert_not_reached ();
12210         }
12211
12212         return -1;
12213 }
12214
12215 int
12216 mono_load_membase_to_load_mem (int opcode)
12217 {
12218         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12219 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12220         switch (opcode) {
12221         case OP_LOAD_MEMBASE:
12222                 return OP_LOAD_MEM;
12223         case OP_LOADU1_MEMBASE:
12224                 return OP_LOADU1_MEM;
12225         case OP_LOADU2_MEMBASE:
12226                 return OP_LOADU2_MEM;
12227         case OP_LOADI4_MEMBASE:
12228                 return OP_LOADI4_MEM;
12229         case OP_LOADU4_MEMBASE:
12230                 return OP_LOADU4_MEM;
12231 #if SIZEOF_REGISTER == 8
12232         case OP_LOADI8_MEMBASE:
12233                 return OP_LOADI8_MEM;
12234 #endif
12235         }
12236 #endif
12237
12238         return -1;
12239 }
12240
12241 static inline int
12242 op_to_op_dest_membase (int store_opcode, int opcode)
12243 {
12244 #if defined(TARGET_X86)
12245         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12246                 return -1;
12247
12248         switch (opcode) {
12249         case OP_IADD:
12250                 return OP_X86_ADD_MEMBASE_REG;
12251         case OP_ISUB:
12252                 return OP_X86_SUB_MEMBASE_REG;
12253         case OP_IAND:
12254                 return OP_X86_AND_MEMBASE_REG;
12255         case OP_IOR:
12256                 return OP_X86_OR_MEMBASE_REG;
12257         case OP_IXOR:
12258                 return OP_X86_XOR_MEMBASE_REG;
12259         case OP_ADD_IMM:
12260         case OP_IADD_IMM:
12261                 return OP_X86_ADD_MEMBASE_IMM;
12262         case OP_SUB_IMM:
12263         case OP_ISUB_IMM:
12264                 return OP_X86_SUB_MEMBASE_IMM;
12265         case OP_AND_IMM:
12266         case OP_IAND_IMM:
12267                 return OP_X86_AND_MEMBASE_IMM;
12268         case OP_OR_IMM:
12269         case OP_IOR_IMM:
12270                 return OP_X86_OR_MEMBASE_IMM;
12271         case OP_XOR_IMM:
12272         case OP_IXOR_IMM:
12273                 return OP_X86_XOR_MEMBASE_IMM;
12274         case OP_MOVE:
12275                 return OP_NOP;
12276         }
12277 #endif
12278
12279 #if defined(TARGET_AMD64)
12280         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12281                 return -1;
12282
12283         switch (opcode) {
12284         case OP_IADD:
12285                 return OP_X86_ADD_MEMBASE_REG;
12286         case OP_ISUB:
12287                 return OP_X86_SUB_MEMBASE_REG;
12288         case OP_IAND:
12289                 return OP_X86_AND_MEMBASE_REG;
12290         case OP_IOR:
12291                 return OP_X86_OR_MEMBASE_REG;
12292         case OP_IXOR:
12293                 return OP_X86_XOR_MEMBASE_REG;
12294         case OP_IADD_IMM:
12295                 return OP_X86_ADD_MEMBASE_IMM;
12296         case OP_ISUB_IMM:
12297                 return OP_X86_SUB_MEMBASE_IMM;
12298         case OP_IAND_IMM:
12299                 return OP_X86_AND_MEMBASE_IMM;
12300         case OP_IOR_IMM:
12301                 return OP_X86_OR_MEMBASE_IMM;
12302         case OP_IXOR_IMM:
12303                 return OP_X86_XOR_MEMBASE_IMM;
12304         case OP_LADD:
12305                 return OP_AMD64_ADD_MEMBASE_REG;
12306         case OP_LSUB:
12307                 return OP_AMD64_SUB_MEMBASE_REG;
12308         case OP_LAND:
12309                 return OP_AMD64_AND_MEMBASE_REG;
12310         case OP_LOR:
12311                 return OP_AMD64_OR_MEMBASE_REG;
12312         case OP_LXOR:
12313                 return OP_AMD64_XOR_MEMBASE_REG;
12314         case OP_ADD_IMM:
12315         case OP_LADD_IMM:
12316                 return OP_AMD64_ADD_MEMBASE_IMM;
12317         case OP_SUB_IMM:
12318         case OP_LSUB_IMM:
12319                 return OP_AMD64_SUB_MEMBASE_IMM;
12320         case OP_AND_IMM:
12321         case OP_LAND_IMM:
12322                 return OP_AMD64_AND_MEMBASE_IMM;
12323         case OP_OR_IMM:
12324         case OP_LOR_IMM:
12325                 return OP_AMD64_OR_MEMBASE_IMM;
12326         case OP_XOR_IMM:
12327         case OP_LXOR_IMM:
12328                 return OP_AMD64_XOR_MEMBASE_IMM;
12329         case OP_MOVE:
12330                 return OP_NOP;
12331         }
12332 #endif
12333
12334         return -1;
12335 }
12336
12337 static inline int
12338 op_to_op_store_membase (int store_opcode, int opcode)
12339 {
12340 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12341         switch (opcode) {
12342         case OP_ICEQ:
12343                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12344                         return OP_X86_SETEQ_MEMBASE;
12345         case OP_CNE:
12346                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12347                         return OP_X86_SETNE_MEMBASE;
12348         }
12349 #endif
12350
12351         return -1;
12352 }
12353
12354 static inline int
12355 op_to_op_src1_membase (int load_opcode, int opcode)
12356 {
12357 #ifdef TARGET_X86
12358         /* FIXME: This has sign extension issues */
12359         /*
12360         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12361                 return OP_X86_COMPARE_MEMBASE8_IMM;
12362         */
12363
12364         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12365                 return -1;
12366
12367         switch (opcode) {
12368         case OP_X86_PUSH:
12369                 return OP_X86_PUSH_MEMBASE;
12370         case OP_COMPARE_IMM:
12371         case OP_ICOMPARE_IMM:
12372                 return OP_X86_COMPARE_MEMBASE_IMM;
12373         case OP_COMPARE:
12374         case OP_ICOMPARE:
12375                 return OP_X86_COMPARE_MEMBASE_REG;
12376         }
12377 #endif
12378
12379 #ifdef TARGET_AMD64
12380         /* FIXME: This has sign extension issues */
12381         /*
12382         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12383                 return OP_X86_COMPARE_MEMBASE8_IMM;
12384         */
12385
12386         switch (opcode) {
12387         case OP_X86_PUSH:
12388 #ifdef __mono_ilp32__
12389                 if (load_opcode == OP_LOADI8_MEMBASE)
12390 #else
12391                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12392 #endif
12393                         return OP_X86_PUSH_MEMBASE;
12394                 break;
12395                 /* FIXME: This only works for 32 bit immediates
12396         case OP_COMPARE_IMM:
12397         case OP_LCOMPARE_IMM:
12398                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12399                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12400                 */
12401         case OP_ICOMPARE_IMM:
12402                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12403                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12404                 break;
12405         case OP_COMPARE:
12406         case OP_LCOMPARE:
12407 #ifdef __mono_ilp32__
12408                 if (load_opcode == OP_LOAD_MEMBASE)
12409                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12410                 if (load_opcode == OP_LOADI8_MEMBASE)
12411 #else
12412                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12413 #endif
12414                         return OP_AMD64_COMPARE_MEMBASE_REG;
12415                 break;
12416         case OP_ICOMPARE:
12417                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12418                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12419                 break;
12420         }
12421 #endif
12422
12423         return -1;
12424 }
12425
12426 static inline int
12427 op_to_op_src2_membase (int load_opcode, int opcode)
12428 {
12429 #ifdef TARGET_X86
12430         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12431                 return -1;
12432         
12433         switch (opcode) {
12434         case OP_COMPARE:
12435         case OP_ICOMPARE:
12436                 return OP_X86_COMPARE_REG_MEMBASE;
12437         case OP_IADD:
12438                 return OP_X86_ADD_REG_MEMBASE;
12439         case OP_ISUB:
12440                 return OP_X86_SUB_REG_MEMBASE;
12441         case OP_IAND:
12442                 return OP_X86_AND_REG_MEMBASE;
12443         case OP_IOR:
12444                 return OP_X86_OR_REG_MEMBASE;
12445         case OP_IXOR:
12446                 return OP_X86_XOR_REG_MEMBASE;
12447         }
12448 #endif
12449
12450 #ifdef TARGET_AMD64
12451 #ifdef __mono_ilp32__
12452         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12453 #else
12454         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12455 #endif
12456                 switch (opcode) {
12457                 case OP_ICOMPARE:
12458                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12459                 case OP_IADD:
12460                         return OP_X86_ADD_REG_MEMBASE;
12461                 case OP_ISUB:
12462                         return OP_X86_SUB_REG_MEMBASE;
12463                 case OP_IAND:
12464                         return OP_X86_AND_REG_MEMBASE;
12465                 case OP_IOR:
12466                         return OP_X86_OR_REG_MEMBASE;
12467                 case OP_IXOR:
12468                         return OP_X86_XOR_REG_MEMBASE;
12469                 }
12470 #ifdef __mono_ilp32__
12471         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12472 #else
12473         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12474 #endif
12475                 switch (opcode) {
12476                 case OP_COMPARE:
12477                 case OP_LCOMPARE:
12478                         return OP_AMD64_COMPARE_REG_MEMBASE;
12479                 case OP_LADD:
12480                         return OP_AMD64_ADD_REG_MEMBASE;
12481                 case OP_LSUB:
12482                         return OP_AMD64_SUB_REG_MEMBASE;
12483                 case OP_LAND:
12484                         return OP_AMD64_AND_REG_MEMBASE;
12485                 case OP_LOR:
12486                         return OP_AMD64_OR_REG_MEMBASE;
12487                 case OP_LXOR:
12488                         return OP_AMD64_XOR_REG_MEMBASE;
12489                 }
12490         }
12491 #endif
12492
12493         return -1;
12494 }
12495
12496 int
12497 mono_op_to_op_imm_noemul (int opcode)
12498 {
12499         switch (opcode) {
12500 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12501         case OP_LSHR:
12502         case OP_LSHL:
12503         case OP_LSHR_UN:
12504                 return -1;
12505 #endif
12506 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12507         case OP_IDIV:
12508         case OP_IDIV_UN:
12509         case OP_IREM:
12510         case OP_IREM_UN:
12511                 return -1;
12512 #endif
12513 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12514         case OP_IMUL:
12515                 return -1;
12516 #endif
12517         default:
12518                 return mono_op_to_op_imm (opcode);
12519         }
12520 }
12521
12522 /**
12523  * mono_handle_global_vregs:
12524  *
12525  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12526  * for them.
12527  */
12528 void
12529 mono_handle_global_vregs (MonoCompile *cfg)
12530 {
12531         gint32 *vreg_to_bb;
12532         MonoBasicBlock *bb;
12533         int i, pos;
12534
12535         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12536
12537 #ifdef MONO_ARCH_SIMD_INTRINSICS
12538         if (cfg->uses_simd_intrinsics)
12539                 mono_simd_simplify_indirection (cfg);
12540 #endif
12541
12542         /* Find local vregs used in more than one bb */
12543         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12544                 MonoInst *ins = bb->code;       
12545                 int block_num = bb->block_num;
12546
12547                 if (cfg->verbose_level > 2)
12548                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12549
12550                 cfg->cbb = bb;
12551                 for (; ins; ins = ins->next) {
12552                         const char *spec = INS_INFO (ins->opcode);
12553                         int regtype = 0, regindex;
12554                         gint32 prev_bb;
12555
12556                         if (G_UNLIKELY (cfg->verbose_level > 2))
12557                                 mono_print_ins (ins);
12558
12559                         g_assert (ins->opcode >= MONO_CEE_LAST);
12560
12561                         for (regindex = 0; regindex < 4; regindex ++) {
12562                                 int vreg = 0;
12563
12564                                 if (regindex == 0) {
12565                                         regtype = spec [MONO_INST_DEST];
12566                                         if (regtype == ' ')
12567                                                 continue;
12568                                         vreg = ins->dreg;
12569                                 } else if (regindex == 1) {
12570                                         regtype = spec [MONO_INST_SRC1];
12571                                         if (regtype == ' ')
12572                                                 continue;
12573                                         vreg = ins->sreg1;
12574                                 } else if (regindex == 2) {
12575                                         regtype = spec [MONO_INST_SRC2];
12576                                         if (regtype == ' ')
12577                                                 continue;
12578                                         vreg = ins->sreg2;
12579                                 } else if (regindex == 3) {
12580                                         regtype = spec [MONO_INST_SRC3];
12581                                         if (regtype == ' ')
12582                                                 continue;
12583                                         vreg = ins->sreg3;
12584                                 }
12585
12586 #if SIZEOF_REGISTER == 4
12587                                 /* In the LLVM case, the long opcodes are not decomposed */
12588                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12589                                         /*
12590                                          * Since some instructions reference the original long vreg,
12591                                          * and some reference the two component vregs, it is quite hard
12592                                          * to determine when it needs to be global. So be conservative.
12593                                          */
12594                                         if (!get_vreg_to_inst (cfg, vreg)) {
12595                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12596
12597                                                 if (cfg->verbose_level > 2)
12598                                                         printf ("LONG VREG R%d made global.\n", vreg);
12599                                         }
12600
12601                                         /*
12602                                          * Make the component vregs volatile since the optimizations can
12603                                          * get confused otherwise.
12604                                          */
12605                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12606                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12607                                 }
12608 #endif
12609
12610                                 g_assert (vreg != -1);
12611
12612                                 prev_bb = vreg_to_bb [vreg];
12613                                 if (prev_bb == 0) {
12614                                         /* 0 is a valid block num */
12615                                         vreg_to_bb [vreg] = block_num + 1;
12616                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12617                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12618                                                 continue;
12619
12620                                         if (!get_vreg_to_inst (cfg, vreg)) {
12621                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12622                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12623
12624                                                 switch (regtype) {
12625                                                 case 'i':
12626                                                         if (vreg_is_ref (cfg, vreg))
12627                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12628                                                         else
12629                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12630                                                         break;
12631                                                 case 'l':
12632                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12633                                                         break;
12634                                                 case 'f':
12635                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12636                                                         break;
12637                                                 case 'v':
12638                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12639                                                         break;
12640                                                 default:
12641                                                         g_assert_not_reached ();
12642                                                 }
12643                                         }
12644
12645                                         /* Flag as having been used in more than one bb */
12646                                         vreg_to_bb [vreg] = -1;
12647                                 }
12648                         }
12649                 }
12650         }
12651
12652         /* If a variable is used in only one bblock, convert it into a local vreg */
12653         for (i = 0; i < cfg->num_varinfo; i++) {
12654                 MonoInst *var = cfg->varinfo [i];
12655                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12656
12657                 switch (var->type) {
12658                 case STACK_I4:
12659                 case STACK_OBJ:
12660                 case STACK_PTR:
12661                 case STACK_MP:
12662                 case STACK_VTYPE:
12663 #if SIZEOF_REGISTER == 8
12664                 case STACK_I8:
12665 #endif
12666 #if !defined(TARGET_X86)
12667                 /* Enabling this screws up the fp stack on x86 */
12668                 case STACK_R8:
12669 #endif
12670                         if (mono_arch_is_soft_float ())
12671                                 break;
12672
12673                         /* Arguments are implicitly global */
12674                         /* Putting R4 vars into registers doesn't work currently */
12675                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12676                         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) {
12677                                 /* 
12678                                  * Make that the variable's liveness interval doesn't contain a call, since
12679                                  * that would cause the lvreg to be spilled, making the whole optimization
12680                                  * useless.
12681                                  */
12682                                 /* This is too slow for JIT compilation */
12683 #if 0
12684                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12685                                         MonoInst *ins;
12686                                         int def_index, call_index, ins_index;
12687                                         gboolean spilled = FALSE;
12688
12689                                         def_index = -1;
12690                                         call_index = -1;
12691                                         ins_index = 0;
12692                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12693                                                 const char *spec = INS_INFO (ins->opcode);
12694
12695                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12696                                                         def_index = ins_index;
12697
12698                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12699                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12700                                                         if (call_index > def_index) {
12701                                                                 spilled = TRUE;
12702                                                                 break;
12703                                                         }
12704                                                 }
12705
12706                                                 if (MONO_IS_CALL (ins))
12707                                                         call_index = ins_index;
12708
12709                                                 ins_index ++;
12710                                         }
12711
12712                                         if (spilled)
12713                                                 break;
12714                                 }
12715 #endif
12716
12717                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12718                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12719                                 var->flags |= MONO_INST_IS_DEAD;
12720                                 cfg->vreg_to_inst [var->dreg] = NULL;
12721                         }
12722                         break;
12723                 }
12724         }
12725
12726         /* 
12727          * Compress the varinfo and vars tables so the liveness computation is faster and
12728          * takes up less space.
12729          */
12730         pos = 0;
12731         for (i = 0; i < cfg->num_varinfo; ++i) {
12732                 MonoInst *var = cfg->varinfo [i];
12733                 if (pos < i && cfg->locals_start == i)
12734                         cfg->locals_start = pos;
12735                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12736                         if (pos < i) {
12737                                 cfg->varinfo [pos] = cfg->varinfo [i];
12738                                 cfg->varinfo [pos]->inst_c0 = pos;
12739                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12740                                 cfg->vars [pos].idx = pos;
12741 #if SIZEOF_REGISTER == 4
12742                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12743                                         /* Modify the two component vars too */
12744                                         MonoInst *var1;
12745
12746                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12747                                         var1->inst_c0 = pos;
12748                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12749                                         var1->inst_c0 = pos;
12750                                 }
12751 #endif
12752                         }
12753                         pos ++;
12754                 }
12755         }
12756         cfg->num_varinfo = pos;
12757         if (cfg->locals_start > cfg->num_varinfo)
12758                 cfg->locals_start = cfg->num_varinfo;
12759 }
12760
12761 /**
12762  * mono_spill_global_vars:
12763  *
12764  *   Generate spill code for variables which are not allocated to registers, 
12765  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12766  * code is generated which could be optimized by the local optimization passes.
12767  */
12768 void
12769 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12770 {
12771         MonoBasicBlock *bb;
12772         char spec2 [16];
12773         int orig_next_vreg;
12774         guint32 *vreg_to_lvreg;
12775         guint32 *lvregs;
12776         guint32 i, lvregs_len;
12777         gboolean dest_has_lvreg = FALSE;
12778         guint32 stacktypes [128];
12779         MonoInst **live_range_start, **live_range_end;
12780         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12781         int *gsharedvt_vreg_to_idx = NULL;
12782
12783         *need_local_opts = FALSE;
12784
12785         memset (spec2, 0, sizeof (spec2));
12786
12787         /* FIXME: Move this function to mini.c */
12788         stacktypes ['i'] = STACK_PTR;
12789         stacktypes ['l'] = STACK_I8;
12790         stacktypes ['f'] = STACK_R8;
12791 #ifdef MONO_ARCH_SIMD_INTRINSICS
12792         stacktypes ['x'] = STACK_VTYPE;
12793 #endif
12794
12795 #if SIZEOF_REGISTER == 4
12796         /* Create MonoInsts for longs */
12797         for (i = 0; i < cfg->num_varinfo; i++) {
12798                 MonoInst *ins = cfg->varinfo [i];
12799
12800                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12801                         switch (ins->type) {
12802                         case STACK_R8:
12803                         case STACK_I8: {
12804                                 MonoInst *tree;
12805
12806                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12807                                         break;
12808
12809                                 g_assert (ins->opcode == OP_REGOFFSET);
12810
12811                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12812                                 g_assert (tree);
12813                                 tree->opcode = OP_REGOFFSET;
12814                                 tree->inst_basereg = ins->inst_basereg;
12815                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12816
12817                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12818                                 g_assert (tree);
12819                                 tree->opcode = OP_REGOFFSET;
12820                                 tree->inst_basereg = ins->inst_basereg;
12821                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12822                                 break;
12823                         }
12824                         default:
12825                                 break;
12826                         }
12827                 }
12828         }
12829 #endif
12830
12831         if (cfg->compute_gc_maps) {
12832                 /* registers need liveness info even for !non refs */
12833                 for (i = 0; i < cfg->num_varinfo; i++) {
12834                         MonoInst *ins = cfg->varinfo [i];
12835
12836                         if (ins->opcode == OP_REGVAR)
12837                                 ins->flags |= MONO_INST_GC_TRACK;
12838                 }
12839         }
12840
12841         if (cfg->gsharedvt) {
12842                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
12843
12844                 for (i = 0; i < cfg->num_varinfo; ++i) {
12845                         MonoInst *ins = cfg->varinfo [i];
12846                         int idx;
12847
12848                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12849                                 if (i >= cfg->locals_start) {
12850                                         /* Local */
12851                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
12852                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
12853                                         ins->opcode = OP_GSHAREDVT_LOCAL;
12854                                         ins->inst_imm = idx;
12855                                 } else {
12856                                         /* Arg */
12857                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
12858                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
12859                                 }
12860                         }
12861                 }
12862         }
12863                 
12864         /* FIXME: widening and truncation */
12865
12866         /*
12867          * As an optimization, when a variable allocated to the stack is first loaded into 
12868          * an lvreg, we will remember the lvreg and use it the next time instead of loading
12869          * the variable again.
12870          */
12871         orig_next_vreg = cfg->next_vreg;
12872         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
12873         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
12874         lvregs_len = 0;
12875
12876         /* 
12877          * These arrays contain the first and last instructions accessing a given
12878          * variable.
12879          * Since we emit bblocks in the same order we process them here, and we
12880          * don't split live ranges, these will precisely describe the live range of
12881          * the variable, i.e. the instruction range where a valid value can be found
12882          * in the variables location.
12883          * The live range is computed using the liveness info computed by the liveness pass.
12884          * We can't use vmv->range, since that is an abstract live range, and we need
12885          * one which is instruction precise.
12886          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
12887          */
12888         /* FIXME: Only do this if debugging info is requested */
12889         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
12890         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
12891         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12892         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12893         
12894         /* Add spill loads/stores */
12895         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12896                 MonoInst *ins;
12897
12898                 if (cfg->verbose_level > 2)
12899                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
12900
12901                 /* Clear vreg_to_lvreg array */
12902                 for (i = 0; i < lvregs_len; i++)
12903                         vreg_to_lvreg [lvregs [i]] = 0;
12904                 lvregs_len = 0;
12905
12906                 cfg->cbb = bb;
12907                 MONO_BB_FOR_EACH_INS (bb, ins) {
12908                         const char *spec = INS_INFO (ins->opcode);
12909                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
12910                         gboolean store, no_lvreg;
12911                         int sregs [MONO_MAX_SRC_REGS];
12912
12913                         if (G_UNLIKELY (cfg->verbose_level > 2))
12914                                 mono_print_ins (ins);
12915
12916                         if (ins->opcode == OP_NOP)
12917                                 continue;
12918
12919                         /* 
12920                          * We handle LDADDR here as well, since it can only be decomposed
12921                          * when variable addresses are known.
12922                          */
12923                         if (ins->opcode == OP_LDADDR) {
12924                                 MonoInst *var = ins->inst_p0;
12925
12926                                 if (var->opcode == OP_VTARG_ADDR) {
12927                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
12928                                         MonoInst *vtaddr = var->inst_left;
12929                                         if (vtaddr->opcode == OP_REGVAR) {
12930                                                 ins->opcode = OP_MOVE;
12931                                                 ins->sreg1 = vtaddr->dreg;
12932                                         }
12933                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
12934                                                 ins->opcode = OP_LOAD_MEMBASE;
12935                                                 ins->inst_basereg = vtaddr->inst_basereg;
12936                                                 ins->inst_offset = vtaddr->inst_offset;
12937                                         } else
12938                                                 NOT_IMPLEMENTED;
12939                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
12940                                         /* gsharedvt arg passed by ref */
12941                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
12942
12943                                         ins->opcode = OP_LOAD_MEMBASE;
12944                                         ins->inst_basereg = var->inst_basereg;
12945                                         ins->inst_offset = var->inst_offset;
12946                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
12947                                         MonoInst *load, *load2, *load3;
12948                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
12949                                         int reg1, reg2, reg3;
12950                                         MonoInst *info_var = cfg->gsharedvt_info_var;
12951                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
12952
12953                                         /*
12954                                          * gsharedvt local.
12955                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
12956                                          */
12957
12958                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
12959
12960                                         g_assert (info_var);
12961                                         g_assert (locals_var);
12962
12963                                         /* Mark the instruction used to compute the locals var as used */
12964                                         cfg->gsharedvt_locals_var_ins = NULL;
12965
12966                                         /* Load the offset */
12967                                         if (info_var->opcode == OP_REGOFFSET) {
12968                                                 reg1 = alloc_ireg (cfg);
12969                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
12970                                         } else if (info_var->opcode == OP_REGVAR) {
12971                                                 load = NULL;
12972                                                 reg1 = info_var->dreg;
12973                                         } else {
12974                                                 g_assert_not_reached ();
12975                                         }
12976                                         reg2 = alloc_ireg (cfg);
12977                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
12978                                         /* Load the locals area address */
12979                                         reg3 = alloc_ireg (cfg);
12980                                         if (locals_var->opcode == OP_REGOFFSET) {
12981                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
12982                                         } else if (locals_var->opcode == OP_REGVAR) {
12983                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
12984                                         } else {
12985                                                 g_assert_not_reached ();
12986                                         }
12987                                         /* Compute the address */
12988                                         ins->opcode = OP_PADD;
12989                                         ins->sreg1 = reg3;
12990                                         ins->sreg2 = reg2;
12991
12992                                         mono_bblock_insert_before_ins (bb, ins, load3);
12993                                         mono_bblock_insert_before_ins (bb, load3, load2);
12994                                         if (load)
12995                                                 mono_bblock_insert_before_ins (bb, load2, load);
12996                                 } else {
12997                                         g_assert (var->opcode == OP_REGOFFSET);
12998
12999                                         ins->opcode = OP_ADD_IMM;
13000                                         ins->sreg1 = var->inst_basereg;
13001                                         ins->inst_imm = var->inst_offset;
13002                                 }
13003
13004                                 *need_local_opts = TRUE;
13005                                 spec = INS_INFO (ins->opcode);
13006                         }
13007
13008                         if (ins->opcode < MONO_CEE_LAST) {
13009                                 mono_print_ins (ins);
13010                                 g_assert_not_reached ();
13011                         }
13012
13013                         /*
13014                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13015                          * src register.
13016                          * FIXME:
13017                          */
13018                         if (MONO_IS_STORE_MEMBASE (ins)) {
13019                                 tmp_reg = ins->dreg;
13020                                 ins->dreg = ins->sreg2;
13021                                 ins->sreg2 = tmp_reg;
13022                                 store = TRUE;
13023
13024                                 spec2 [MONO_INST_DEST] = ' ';
13025                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13026                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13027                                 spec2 [MONO_INST_SRC3] = ' ';
13028                                 spec = spec2;
13029                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13030                                 g_assert_not_reached ();
13031                         else
13032                                 store = FALSE;
13033                         no_lvreg = FALSE;
13034
13035                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13036                                 printf ("\t %.3s %d", spec, ins->dreg);
13037                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13038                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13039                                         printf (" %d", sregs [srcindex]);
13040                                 printf ("\n");
13041                         }
13042
13043                         /***************/
13044                         /*    DREG     */
13045                         /***************/
13046                         regtype = spec [MONO_INST_DEST];
13047                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13048                         prev_dreg = -1;
13049
13050                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13051                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13052                                 MonoInst *store_ins;
13053                                 int store_opcode;
13054                                 MonoInst *def_ins = ins;
13055                                 int dreg = ins->dreg; /* The original vreg */
13056
13057                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13058
13059                                 if (var->opcode == OP_REGVAR) {
13060                                         ins->dreg = var->dreg;
13061                                 } 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)) {
13062                                         /* 
13063                                          * Instead of emitting a load+store, use a _membase opcode.
13064                                          */
13065                                         g_assert (var->opcode == OP_REGOFFSET);
13066                                         if (ins->opcode == OP_MOVE) {
13067                                                 NULLIFY_INS (ins);
13068                                                 def_ins = NULL;
13069                                         } else {
13070                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13071                                                 ins->inst_basereg = var->inst_basereg;
13072                                                 ins->inst_offset = var->inst_offset;
13073                                                 ins->dreg = -1;
13074                                         }
13075                                         spec = INS_INFO (ins->opcode);
13076                                 } else {
13077                                         guint32 lvreg;
13078
13079                                         g_assert (var->opcode == OP_REGOFFSET);
13080
13081                                         prev_dreg = ins->dreg;
13082
13083                                         /* Invalidate any previous lvreg for this vreg */
13084                                         vreg_to_lvreg [ins->dreg] = 0;
13085
13086                                         lvreg = 0;
13087
13088                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13089                                                 regtype = 'l';
13090                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13091                                         }
13092
13093                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13094
13095 #if SIZEOF_REGISTER != 8
13096                                         if (regtype == 'l') {
13097                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13098                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13099                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13100                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13101                                                 def_ins = store_ins;
13102                                         }
13103                                         else
13104 #endif
13105                                         {
13106                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13107
13108                                                 /* Try to fuse the store into the instruction itself */
13109                                                 /* FIXME: Add more instructions */
13110                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13111                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13112                                                         ins->inst_imm = ins->inst_c0;
13113                                                         ins->inst_destbasereg = var->inst_basereg;
13114                                                         ins->inst_offset = var->inst_offset;
13115                                                         spec = INS_INFO (ins->opcode);
13116                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13117                                                         ins->opcode = store_opcode;
13118                                                         ins->inst_destbasereg = var->inst_basereg;
13119                                                         ins->inst_offset = var->inst_offset;
13120
13121                                                         no_lvreg = TRUE;
13122
13123                                                         tmp_reg = ins->dreg;
13124                                                         ins->dreg = ins->sreg2;
13125                                                         ins->sreg2 = tmp_reg;
13126                                                         store = TRUE;
13127
13128                                                         spec2 [MONO_INST_DEST] = ' ';
13129                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13130                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13131                                                         spec2 [MONO_INST_SRC3] = ' ';
13132                                                         spec = spec2;
13133                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13134                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13135                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13136                                                         ins->dreg = -1;
13137                                                         ins->inst_basereg = var->inst_basereg;
13138                                                         ins->inst_offset = var->inst_offset;
13139                                                         spec = INS_INFO (ins->opcode);
13140                                                 } else {
13141                                                         /* printf ("INS: "); mono_print_ins (ins); */
13142                                                         /* Create a store instruction */
13143                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13144
13145                                                         /* Insert it after the instruction */
13146                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13147
13148                                                         def_ins = store_ins;
13149
13150                                                         /* 
13151                                                          * We can't assign ins->dreg to var->dreg here, since the
13152                                                          * sregs could use it. So set a flag, and do it after
13153                                                          * the sregs.
13154                                                          */
13155                                                         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)))
13156                                                                 dest_has_lvreg = TRUE;
13157                                                 }
13158                                         }
13159                                 }
13160
13161                                 if (def_ins && !live_range_start [dreg]) {
13162                                         live_range_start [dreg] = def_ins;
13163                                         live_range_start_bb [dreg] = bb;
13164                                 }
13165
13166                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13167                                         MonoInst *tmp;
13168
13169                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13170                                         tmp->inst_c1 = dreg;
13171                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13172                                 }
13173                         }
13174
13175                         /************/
13176                         /*  SREGS   */
13177                         /************/
13178                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13179                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13180                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13181                                 sreg = sregs [srcindex];
13182
13183                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13184                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13185                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13186                                         MonoInst *use_ins = ins;
13187                                         MonoInst *load_ins;
13188                                         guint32 load_opcode;
13189
13190                                         if (var->opcode == OP_REGVAR) {
13191                                                 sregs [srcindex] = var->dreg;
13192                                                 //mono_inst_set_src_registers (ins, sregs);
13193                                                 live_range_end [sreg] = use_ins;
13194                                                 live_range_end_bb [sreg] = bb;
13195
13196                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13197                                                         MonoInst *tmp;
13198
13199                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13200                                                         /* var->dreg is a hreg */
13201                                                         tmp->inst_c1 = sreg;
13202                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13203                                                 }
13204
13205                                                 continue;
13206                                         }
13207
13208                                         g_assert (var->opcode == OP_REGOFFSET);
13209                                                 
13210                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13211
13212                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13213
13214                                         if (vreg_to_lvreg [sreg]) {
13215                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13216
13217                                                 /* The variable is already loaded to an lvreg */
13218                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13219                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13220                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13221                                                 //mono_inst_set_src_registers (ins, sregs);
13222                                                 continue;
13223                                         }
13224
13225                                         /* Try to fuse the load into the instruction */
13226                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13227                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13228                                                 sregs [0] = var->inst_basereg;
13229                                                 //mono_inst_set_src_registers (ins, sregs);
13230                                                 ins->inst_offset = var->inst_offset;
13231                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13232                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13233                                                 sregs [1] = var->inst_basereg;
13234                                                 //mono_inst_set_src_registers (ins, sregs);
13235                                                 ins->inst_offset = var->inst_offset;
13236                                         } else {
13237                                                 if (MONO_IS_REAL_MOVE (ins)) {
13238                                                         ins->opcode = OP_NOP;
13239                                                         sreg = ins->dreg;
13240                                                 } else {
13241                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13242
13243                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13244
13245                                                         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) {
13246                                                                 if (var->dreg == prev_dreg) {
13247                                                                         /*
13248                                                                          * sreg refers to the value loaded by the load
13249                                                                          * emitted below, but we need to use ins->dreg
13250                                                                          * since it refers to the store emitted earlier.
13251                                                                          */
13252                                                                         sreg = ins->dreg;
13253                                                                 }
13254                                                                 g_assert (sreg != -1);
13255                                                                 vreg_to_lvreg [var->dreg] = sreg;
13256                                                                 g_assert (lvregs_len < 1024);
13257                                                                 lvregs [lvregs_len ++] = var->dreg;
13258                                                         }
13259                                                 }
13260
13261                                                 sregs [srcindex] = sreg;
13262                                                 //mono_inst_set_src_registers (ins, sregs);
13263
13264 #if SIZEOF_REGISTER != 8
13265                                                 if (regtype == 'l') {
13266                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13267                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13268                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13269                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13270                                                         use_ins = load_ins;
13271                                                 }
13272                                                 else
13273 #endif
13274                                                 {
13275 #if SIZEOF_REGISTER == 4
13276                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13277 #endif
13278                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13279                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13280                                                         use_ins = load_ins;
13281                                                 }
13282                                         }
13283
13284                                         if (var->dreg < orig_next_vreg) {
13285                                                 live_range_end [var->dreg] = use_ins;
13286                                                 live_range_end_bb [var->dreg] = bb;
13287                                         }
13288
13289                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13290                                                 MonoInst *tmp;
13291
13292                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13293                                                 tmp->inst_c1 = var->dreg;
13294                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13295                                         }
13296                                 }
13297                         }
13298                         mono_inst_set_src_registers (ins, sregs);
13299
13300                         if (dest_has_lvreg) {
13301                                 g_assert (ins->dreg != -1);
13302                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13303                                 g_assert (lvregs_len < 1024);
13304                                 lvregs [lvregs_len ++] = prev_dreg;
13305                                 dest_has_lvreg = FALSE;
13306                         }
13307
13308                         if (store) {
13309                                 tmp_reg = ins->dreg;
13310                                 ins->dreg = ins->sreg2;
13311                                 ins->sreg2 = tmp_reg;
13312                         }
13313
13314                         if (MONO_IS_CALL (ins)) {
13315                                 /* Clear vreg_to_lvreg array */
13316                                 for (i = 0; i < lvregs_len; i++)
13317                                         vreg_to_lvreg [lvregs [i]] = 0;
13318                                 lvregs_len = 0;
13319                         } else if (ins->opcode == OP_NOP) {
13320                                 ins->dreg = -1;
13321                                 MONO_INST_NULLIFY_SREGS (ins);
13322                         }
13323
13324                         if (cfg->verbose_level > 2)
13325                                 mono_print_ins_index (1, ins);
13326                 }
13327
13328                 /* Extend the live range based on the liveness info */
13329                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13330                         for (i = 0; i < cfg->num_varinfo; i ++) {
13331                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13332
13333                                 if (vreg_is_volatile (cfg, vi->vreg))
13334                                         /* The liveness info is incomplete */
13335                                         continue;
13336
13337                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13338                                         /* Live from at least the first ins of this bb */
13339                                         live_range_start [vi->vreg] = bb->code;
13340                                         live_range_start_bb [vi->vreg] = bb;
13341                                 }
13342
13343                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13344                                         /* Live at least until the last ins of this bb */
13345                                         live_range_end [vi->vreg] = bb->last_ins;
13346                                         live_range_end_bb [vi->vreg] = bb;
13347                                 }
13348                         }
13349                 }
13350         }
13351         
13352 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13353         /*
13354          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13355          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13356          */
13357         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13358                 for (i = 0; i < cfg->num_varinfo; ++i) {
13359                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13360                         MonoInst *ins;
13361
13362                         if (live_range_start [vreg]) {
13363                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13364                                 ins->inst_c0 = i;
13365                                 ins->inst_c1 = vreg;
13366                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13367                         }
13368                         if (live_range_end [vreg]) {
13369                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13370                                 ins->inst_c0 = i;
13371                                 ins->inst_c1 = vreg;
13372                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13373                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13374                                 else
13375                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13376                         }
13377                 }
13378         }
13379 #endif
13380
13381         if (cfg->gsharedvt_locals_var_ins) {
13382                 /* Nullify if unused */
13383                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13384                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13385         }
13386
13387         g_free (live_range_start);
13388         g_free (live_range_end);
13389         g_free (live_range_start_bb);
13390         g_free (live_range_end_bb);
13391 }
13392
13393 /**
13394  * FIXME:
13395  * - use 'iadd' instead of 'int_add'
13396  * - handling ovf opcodes: decompose in method_to_ir.
13397  * - unify iregs/fregs
13398  *   -> partly done, the missing parts are:
13399  *   - a more complete unification would involve unifying the hregs as well, so
13400  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13401  *     would no longer map to the machine hregs, so the code generators would need to
13402  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13403  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13404  *     fp/non-fp branches speeds it up by about 15%.
13405  * - use sext/zext opcodes instead of shifts
13406  * - add OP_ICALL
13407  * - get rid of TEMPLOADs if possible and use vregs instead
13408  * - clean up usage of OP_P/OP_ opcodes
13409  * - cleanup usage of DUMMY_USE
13410  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13411  *   stack
13412  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13413  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13414  * - make sure handle_stack_args () is called before the branch is emitted
13415  * - when the new IR is done, get rid of all unused stuff
13416  * - COMPARE/BEQ as separate instructions or unify them ?
13417  *   - keeping them separate allows specialized compare instructions like
13418  *     compare_imm, compare_membase
13419  *   - most back ends unify fp compare+branch, fp compare+ceq
13420  * - integrate mono_save_args into inline_method
13421  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13422  * - handle long shift opts on 32 bit platforms somehow: they require 
13423  *   3 sregs (2 for arg1 and 1 for arg2)
13424  * - make byref a 'normal' type.
13425  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13426  *   variable if needed.
13427  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13428  *   like inline_method.
13429  * - remove inlining restrictions
13430  * - fix LNEG and enable cfold of INEG
13431  * - generalize x86 optimizations like ldelema as a peephole optimization
13432  * - add store_mem_imm for amd64
13433  * - optimize the loading of the interruption flag in the managed->native wrappers
13434  * - avoid special handling of OP_NOP in passes
13435  * - move code inserting instructions into one function/macro.
13436  * - try a coalescing phase after liveness analysis
13437  * - add float -> vreg conversion + local optimizations on !x86
13438  * - figure out how to handle decomposed branches during optimizations, ie.
13439  *   compare+branch, op_jump_table+op_br etc.
13440  * - promote RuntimeXHandles to vregs
13441  * - vtype cleanups:
13442  *   - add a NEW_VARLOADA_VREG macro
13443  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13444  *   accessing vtype fields.
13445  * - get rid of I8CONST on 64 bit platforms
13446  * - dealing with the increase in code size due to branches created during opcode
13447  *   decomposition:
13448  *   - use extended basic blocks
13449  *     - all parts of the JIT
13450  *     - handle_global_vregs () && local regalloc
13451  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13452  * - sources of increase in code size:
13453  *   - vtypes
13454  *   - long compares
13455  *   - isinst and castclass
13456  *   - lvregs not allocated to global registers even if used multiple times
13457  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13458  *   meaningful.
13459  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13460  * - add all micro optimizations from the old JIT
13461  * - put tree optimizations into the deadce pass
13462  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13463  *   specific function.
13464  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13465  *   fcompare + branchCC.
13466  * - create a helper function for allocating a stack slot, taking into account 
13467  *   MONO_CFG_HAS_SPILLUP.
13468  * - merge r68207.
13469  * - merge the ia64 switch changes.
13470  * - optimize mono_regstate2_alloc_int/float.
13471  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13472  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13473  *   parts of the tree could be separated by other instructions, killing the tree
13474  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13475  *   instructions if the result of the load is used multiple times ?
13476  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13477  * - LAST MERGE: 108395.
13478  * - when returning vtypes in registers, generate IR and append it to the end of the
13479  *   last bb instead of doing it in the epilog.
13480  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13481  */
13482
13483 /*
13484
13485 NOTES
13486 -----
13487
13488 - When to decompose opcodes:
13489   - earlier: this makes some optimizations hard to implement, since the low level IR
13490   no longer contains the neccessary information. But it is easier to do.
13491   - later: harder to implement, enables more optimizations.
13492 - Branches inside bblocks:
13493   - created when decomposing complex opcodes. 
13494     - branches to another bblock: harmless, but not tracked by the branch 
13495       optimizations, so need to branch to a label at the start of the bblock.
13496     - branches to inside the same bblock: very problematic, trips up the local
13497       reg allocator. Can be fixed by spitting the current bblock, but that is a
13498       complex operation, since some local vregs can become global vregs etc.
13499 - Local/global vregs:
13500   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13501     local register allocator.
13502   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13503     structure, created by mono_create_var (). Assigned to hregs or the stack by
13504     the global register allocator.
13505 - When to do optimizations like alu->alu_imm:
13506   - earlier -> saves work later on since the IR will be smaller/simpler
13507   - later -> can work on more instructions
13508 - Handling of valuetypes:
13509   - When a vtype is pushed on the stack, a new temporary is created, an 
13510     instruction computing its address (LDADDR) is emitted and pushed on
13511     the stack. Need to optimize cases when the vtype is used immediately as in
13512     argument passing, stloc etc.
13513 - Instead of the to_end stuff in the old JIT, simply call the function handling
13514   the values on the stack before emitting the last instruction of the bb.
13515 */
13516
13517 #endif /* DISABLE_JIT */