[jit] Add a 'check-pinvoke-callconv' MONO_DEBUG option to check for cdecl/stdcall...
[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 #ifdef HOST_WIN32
1938                 ins = mono_get_jit_tls_intrinsic (cfg);
1939                 if (ins) {
1940                         int jit_tls_dreg = ins->dreg;
1941
1942                         MONO_ADD_INS (cfg->cbb, ins);
1943                         lmf_reg = alloc_preg (cfg);
1944                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
1945                 } else {
1946                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1947                 }
1948 #else
1949                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1950                 if (lmf_ins) 
1951                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1952                 else
1953                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1954 #endif
1955                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1956
1957                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1958                 lmf_reg = ins->dreg;
1959
1960                 prev_lmf_reg = alloc_preg (cfg);
1961                 /* Save previous_lmf */
1962                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1963                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1964                 /* Set new lmf */
1965                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1966         }
1967 }
1968
1969 /*
1970  * emit_pop_lmf:
1971  *
1972  *   Emit IR to pop the current LMF from the LMF stack.
1973  */
1974 static void
1975 emit_pop_lmf (MonoCompile *cfg)
1976 {
1977         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1978         MonoInst *ins;
1979
1980         if (!cfg->lmf_ir)
1981                 return;
1982
1983         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1984         lmf_reg = ins->dreg;
1985
1986         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1987                 /* Load previous_lmf */
1988                 prev_lmf_reg = alloc_preg (cfg);
1989                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1990                 /* Set new LMF */
1991                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1992         } else {
1993                 /*
1994                  * Emit IR to pop the LMF:
1995                  * *(lmf->lmf_addr) = lmf->prev_lmf
1996                  */
1997                 /* This could be called before emit_push_lmf () */
1998                 if (!cfg->lmf_addr_var)
1999                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2000                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2001
2002                 prev_lmf_reg = alloc_preg (cfg);
2003                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2004                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2005         }
2006 }
2007
2008 static int
2009 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2010 {
2011         if (type->byref)
2012                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2013
2014 handle_enum:
2015         type = mini_get_basic_type_from_generic (gsctx, type);
2016         type = mini_replace_type (type);
2017         switch (type->type) {
2018         case MONO_TYPE_VOID:
2019                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2020         case MONO_TYPE_I1:
2021         case MONO_TYPE_U1:
2022         case MONO_TYPE_BOOLEAN:
2023         case MONO_TYPE_I2:
2024         case MONO_TYPE_U2:
2025         case MONO_TYPE_CHAR:
2026         case MONO_TYPE_I4:
2027         case MONO_TYPE_U4:
2028                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2029         case MONO_TYPE_I:
2030         case MONO_TYPE_U:
2031         case MONO_TYPE_PTR:
2032         case MONO_TYPE_FNPTR:
2033                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2034         case MONO_TYPE_CLASS:
2035         case MONO_TYPE_STRING:
2036         case MONO_TYPE_OBJECT:
2037         case MONO_TYPE_SZARRAY:
2038         case MONO_TYPE_ARRAY:    
2039                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2040         case MONO_TYPE_I8:
2041         case MONO_TYPE_U8:
2042                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2043         case MONO_TYPE_R4:
2044         case MONO_TYPE_R8:
2045                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2046         case MONO_TYPE_VALUETYPE:
2047                 if (type->data.klass->enumtype) {
2048                         type = mono_class_enum_basetype (type->data.klass);
2049                         goto handle_enum;
2050                 } else
2051                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2052         case MONO_TYPE_TYPEDBYREF:
2053                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2054         case MONO_TYPE_GENERICINST:
2055                 type = &type->data.generic_class->container_class->byval_arg;
2056                 goto handle_enum;
2057         case MONO_TYPE_VAR:
2058         case MONO_TYPE_MVAR:
2059                 /* gsharedvt */
2060                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2061         default:
2062                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2063         }
2064         return -1;
2065 }
2066
2067 /*
2068  * target_type_is_incompatible:
2069  * @cfg: MonoCompile context
2070  *
2071  * Check that the item @arg on the evaluation stack can be stored
2072  * in the target type (can be a local, or field, etc).
2073  * The cfg arg can be used to check if we need verification or just
2074  * validity checks.
2075  *
2076  * Returns: non-0 value if arg can't be stored on a target.
2077  */
2078 static int
2079 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2080 {
2081         MonoType *simple_type;
2082         MonoClass *klass;
2083
2084         target = mini_replace_type (target);
2085         if (target->byref) {
2086                 /* FIXME: check that the pointed to types match */
2087                 if (arg->type == STACK_MP)
2088                         return arg->klass != mono_class_from_mono_type (target);
2089                 if (arg->type == STACK_PTR)
2090                         return 0;
2091                 return 1;
2092         }
2093
2094         simple_type = mono_type_get_underlying_type (target);
2095         switch (simple_type->type) {
2096         case MONO_TYPE_VOID:
2097                 return 1;
2098         case MONO_TYPE_I1:
2099         case MONO_TYPE_U1:
2100         case MONO_TYPE_BOOLEAN:
2101         case MONO_TYPE_I2:
2102         case MONO_TYPE_U2:
2103         case MONO_TYPE_CHAR:
2104         case MONO_TYPE_I4:
2105         case MONO_TYPE_U4:
2106                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2107                         return 1;
2108                 return 0;
2109         case MONO_TYPE_PTR:
2110                 /* STACK_MP is needed when setting pinned locals */
2111                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2112                         return 1;
2113                 return 0;
2114         case MONO_TYPE_I:
2115         case MONO_TYPE_U:
2116         case MONO_TYPE_FNPTR:
2117                 /* 
2118                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2119                  * in native int. (#688008).
2120                  */
2121                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2122                         return 1;
2123                 return 0;
2124         case MONO_TYPE_CLASS:
2125         case MONO_TYPE_STRING:
2126         case MONO_TYPE_OBJECT:
2127         case MONO_TYPE_SZARRAY:
2128         case MONO_TYPE_ARRAY:    
2129                 if (arg->type != STACK_OBJ)
2130                         return 1;
2131                 /* FIXME: check type compatibility */
2132                 return 0;
2133         case MONO_TYPE_I8:
2134         case MONO_TYPE_U8:
2135                 if (arg->type != STACK_I8)
2136                         return 1;
2137                 return 0;
2138         case MONO_TYPE_R4:
2139         case MONO_TYPE_R8:
2140                 if (arg->type != STACK_R8)
2141                         return 1;
2142                 return 0;
2143         case MONO_TYPE_VALUETYPE:
2144                 if (arg->type != STACK_VTYPE)
2145                         return 1;
2146                 klass = mono_class_from_mono_type (simple_type);
2147                 if (klass != arg->klass)
2148                         return 1;
2149                 return 0;
2150         case MONO_TYPE_TYPEDBYREF:
2151                 if (arg->type != STACK_VTYPE)
2152                         return 1;
2153                 klass = mono_class_from_mono_type (simple_type);
2154                 if (klass != arg->klass)
2155                         return 1;
2156                 return 0;
2157         case MONO_TYPE_GENERICINST:
2158                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2159                         if (arg->type != STACK_VTYPE)
2160                                 return 1;
2161                         klass = mono_class_from_mono_type (simple_type);
2162                         if (klass != arg->klass)
2163                                 return 1;
2164                         return 0;
2165                 } else {
2166                         if (arg->type != STACK_OBJ)
2167                                 return 1;
2168                         /* FIXME: check type compatibility */
2169                         return 0;
2170                 }
2171         case MONO_TYPE_VAR:
2172         case MONO_TYPE_MVAR:
2173                 g_assert (cfg->generic_sharing_context);
2174                 if (mini_type_var_is_vt (cfg, simple_type)) {
2175                         if (arg->type != STACK_VTYPE)
2176                                 return 1;
2177                 } else {
2178                         if (arg->type != STACK_OBJ)
2179                                 return 1;
2180                 }
2181                 return 0;
2182         default:
2183                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2184         }
2185         return 1;
2186 }
2187
2188 /*
2189  * Prepare arguments for passing to a function call.
2190  * Return a non-zero value if the arguments can't be passed to the given
2191  * signature.
2192  * The type checks are not yet complete and some conversions may need
2193  * casts on 32 or 64 bit architectures.
2194  *
2195  * FIXME: implement this using target_type_is_incompatible ()
2196  */
2197 static int
2198 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2199 {
2200         MonoType *simple_type;
2201         int i;
2202
2203         if (sig->hasthis) {
2204                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2205                         return 1;
2206                 args++;
2207         }
2208         for (i = 0; i < sig->param_count; ++i) {
2209                 if (sig->params [i]->byref) {
2210                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2211                                 return 1;
2212                         continue;
2213                 }
2214                 simple_type = sig->params [i];
2215                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2216 handle_enum:
2217                 switch (simple_type->type) {
2218                 case MONO_TYPE_VOID:
2219                         return 1;
2220                         continue;
2221                 case MONO_TYPE_I1:
2222                 case MONO_TYPE_U1:
2223                 case MONO_TYPE_BOOLEAN:
2224                 case MONO_TYPE_I2:
2225                 case MONO_TYPE_U2:
2226                 case MONO_TYPE_CHAR:
2227                 case MONO_TYPE_I4:
2228                 case MONO_TYPE_U4:
2229                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2230                                 return 1;
2231                         continue;
2232                 case MONO_TYPE_I:
2233                 case MONO_TYPE_U:
2234                 case MONO_TYPE_PTR:
2235                 case MONO_TYPE_FNPTR:
2236                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2237                                 return 1;
2238                         continue;
2239                 case MONO_TYPE_CLASS:
2240                 case MONO_TYPE_STRING:
2241                 case MONO_TYPE_OBJECT:
2242                 case MONO_TYPE_SZARRAY:
2243                 case MONO_TYPE_ARRAY:    
2244                         if (args [i]->type != STACK_OBJ)
2245                                 return 1;
2246                         continue;
2247                 case MONO_TYPE_I8:
2248                 case MONO_TYPE_U8:
2249                         if (args [i]->type != STACK_I8)
2250                                 return 1;
2251                         continue;
2252                 case MONO_TYPE_R4:
2253                 case MONO_TYPE_R8:
2254                         if (args [i]->type != STACK_R8)
2255                                 return 1;
2256                         continue;
2257                 case MONO_TYPE_VALUETYPE:
2258                         if (simple_type->data.klass->enumtype) {
2259                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2260                                 goto handle_enum;
2261                         }
2262                         if (args [i]->type != STACK_VTYPE)
2263                                 return 1;
2264                         continue;
2265                 case MONO_TYPE_TYPEDBYREF:
2266                         if (args [i]->type != STACK_VTYPE)
2267                                 return 1;
2268                         continue;
2269                 case MONO_TYPE_GENERICINST:
2270                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2271                         goto handle_enum;
2272                 case MONO_TYPE_VAR:
2273                 case MONO_TYPE_MVAR:
2274                         /* gsharedvt */
2275                         if (args [i]->type != STACK_VTYPE)
2276                                 return 1;
2277                         continue;
2278                 default:
2279                         g_error ("unknown type 0x%02x in check_call_signature",
2280                                  simple_type->type);
2281                 }
2282         }
2283         return 0;
2284 }
2285
2286 static int
2287 callvirt_to_call (int opcode)
2288 {
2289         switch (opcode) {
2290         case OP_CALL_MEMBASE:
2291                 return OP_CALL;
2292         case OP_VOIDCALL_MEMBASE:
2293                 return OP_VOIDCALL;
2294         case OP_FCALL_MEMBASE:
2295                 return OP_FCALL;
2296         case OP_VCALL_MEMBASE:
2297                 return OP_VCALL;
2298         case OP_LCALL_MEMBASE:
2299                 return OP_LCALL;
2300         default:
2301                 g_assert_not_reached ();
2302         }
2303
2304         return -1;
2305 }
2306
2307 #ifdef MONO_ARCH_HAVE_IMT
2308 /* Either METHOD or IMT_ARG needs to be set */
2309 static void
2310 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2311 {
2312         int method_reg;
2313
2314         if (COMPILE_LLVM (cfg)) {
2315                 method_reg = alloc_preg (cfg);
2316
2317                 if (imt_arg) {
2318                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2319                 } else if (cfg->compile_aot) {
2320                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2321                 } else {
2322                         MonoInst *ins;
2323                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2324                         ins->inst_p0 = method;
2325                         ins->dreg = method_reg;
2326                         MONO_ADD_INS (cfg->cbb, ins);
2327                 }
2328
2329 #ifdef ENABLE_LLVM
2330                 call->imt_arg_reg = method_reg;
2331 #endif
2332 #ifdef MONO_ARCH_IMT_REG
2333         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2334 #else
2335         /* Need this to keep the IMT arg alive */
2336         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2337 #endif
2338                 return;
2339         }
2340
2341 #ifdef MONO_ARCH_IMT_REG
2342         method_reg = alloc_preg (cfg);
2343
2344         if (imt_arg) {
2345                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2346         } else if (cfg->compile_aot) {
2347                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2348         } else {
2349                 MonoInst *ins;
2350                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2351                 ins->inst_p0 = method;
2352                 ins->dreg = method_reg;
2353                 MONO_ADD_INS (cfg->cbb, ins);
2354         }
2355
2356         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2357 #else
2358         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2359 #endif
2360 }
2361 #endif
2362
2363 static MonoJumpInfo *
2364 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2365 {
2366         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2367
2368         ji->ip.i = ip;
2369         ji->type = type;
2370         ji->data.target = target;
2371
2372         return ji;
2373 }
2374
2375 static int
2376 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2377 {
2378         if (cfg->generic_sharing_context)
2379                 return mono_class_check_context_used (klass);
2380         else
2381                 return 0;
2382 }
2383
2384 static int
2385 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2386 {
2387         if (cfg->generic_sharing_context)
2388                 return mono_method_check_context_used (method);
2389         else
2390                 return 0;
2391 }
2392
2393 /*
2394  * check_method_sharing:
2395  *
2396  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2397  */
2398 static void
2399 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2400 {
2401         gboolean pass_vtable = FALSE;
2402         gboolean pass_mrgctx = FALSE;
2403
2404         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2405                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2406                 gboolean sharable = FALSE;
2407
2408                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2409                         sharable = TRUE;
2410                 } else {
2411                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2412                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2413                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2414
2415                         sharable = sharing_enabled && context_sharable;
2416                 }
2417
2418                 /*
2419                  * Pass vtable iff target method might
2420                  * be shared, which means that sharing
2421                  * is enabled for its class and its
2422                  * context is sharable (and it's not a
2423                  * generic method).
2424                  */
2425                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2426                         pass_vtable = TRUE;
2427         }
2428
2429         if (mini_method_get_context (cmethod) &&
2430                 mini_method_get_context (cmethod)->method_inst) {
2431                 g_assert (!pass_vtable);
2432
2433                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2434                         pass_mrgctx = TRUE;
2435                 } else {
2436                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2437                         MonoGenericContext *context = mini_method_get_context (cmethod);
2438                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2439
2440                         if (sharing_enabled && context_sharable)
2441                                 pass_mrgctx = TRUE;
2442                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2443                                 pass_mrgctx = TRUE;
2444                 }
2445         }
2446
2447         if (out_pass_vtable)
2448                 *out_pass_vtable = pass_vtable;
2449         if (out_pass_mrgctx)
2450                 *out_pass_mrgctx = pass_mrgctx;
2451 }
2452
2453 inline static MonoCallInst *
2454 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2455                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2456 {
2457         MonoType *sig_ret;
2458         MonoCallInst *call;
2459 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2460         int i;
2461 #endif
2462
2463         if (tail)
2464                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2465         else
2466                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2467
2468         call->args = args;
2469         call->signature = sig;
2470         call->rgctx_reg = rgctx;
2471         sig_ret = mini_replace_type (sig->ret);
2472
2473         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2474
2475         if (tail) {
2476                 if (mini_type_is_vtype (cfg, sig_ret)) {
2477                         call->vret_var = cfg->vret_addr;
2478                         //g_assert_not_reached ();
2479                 }
2480         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2481                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2482                 MonoInst *loada;
2483
2484                 temp->backend.is_pinvoke = sig->pinvoke;
2485
2486                 /*
2487                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2488                  * address of return value to increase optimization opportunities.
2489                  * Before vtype decomposition, the dreg of the call ins itself represents the
2490                  * fact the call modifies the return value. After decomposition, the call will
2491                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2492                  * will be transformed into an LDADDR.
2493                  */
2494                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2495                 loada->dreg = alloc_preg (cfg);
2496                 loada->inst_p0 = temp;
2497                 /* We reference the call too since call->dreg could change during optimization */
2498                 loada->inst_p1 = call;
2499                 MONO_ADD_INS (cfg->cbb, loada);
2500
2501                 call->inst.dreg = temp->dreg;
2502
2503                 call->vret_var = loada;
2504         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2505                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2506
2507 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2508         if (COMPILE_SOFT_FLOAT (cfg)) {
2509                 /* 
2510                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2511                  * an icall, but that cannot be done during the call sequence since it would clobber
2512                  * the call registers + the stack. So we do it before emitting the call.
2513                  */
2514                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2515                         MonoType *t;
2516                         MonoInst *in = call->args [i];
2517
2518                         if (i >= sig->hasthis)
2519                                 t = sig->params [i - sig->hasthis];
2520                         else
2521                                 t = &mono_defaults.int_class->byval_arg;
2522                         t = mono_type_get_underlying_type (t);
2523
2524                         if (!t->byref && t->type == MONO_TYPE_R4) {
2525                                 MonoInst *iargs [1];
2526                                 MonoInst *conv;
2527
2528                                 iargs [0] = in;
2529                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2530
2531                                 /* The result will be in an int vreg */
2532                                 call->args [i] = conv;
2533                         }
2534                 }
2535         }
2536 #endif
2537
2538         call->need_unbox_trampoline = unbox_trampoline;
2539
2540 #ifdef ENABLE_LLVM
2541         if (COMPILE_LLVM (cfg))
2542                 mono_llvm_emit_call (cfg, call);
2543         else
2544                 mono_arch_emit_call (cfg, call);
2545 #else
2546         mono_arch_emit_call (cfg, call);
2547 #endif
2548
2549         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2550         cfg->flags |= MONO_CFG_HAS_CALLS;
2551         
2552         return call;
2553 }
2554
2555 static void
2556 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2557 {
2558 #ifdef MONO_ARCH_RGCTX_REG
2559         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2560         cfg->uses_rgctx_reg = TRUE;
2561         call->rgctx_reg = TRUE;
2562 #ifdef ENABLE_LLVM
2563         call->rgctx_arg_reg = rgctx_reg;
2564 #endif
2565 #else
2566         NOT_IMPLEMENTED;
2567 #endif
2568 }       
2569
2570 inline static MonoInst*
2571 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2572 {
2573         MonoCallInst *call;
2574         MonoInst *ins;
2575         int rgctx_reg = -1;
2576         gboolean check_sp = FALSE;
2577
2578         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2579                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2580
2581                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2582                         check_sp = TRUE;
2583         }
2584
2585         if (rgctx_arg) {
2586                 rgctx_reg = mono_alloc_preg (cfg);
2587                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2588         }
2589
2590         if (check_sp) {
2591                 if (!cfg->stack_inbalance_var)
2592                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2593
2594                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2595                 ins->dreg = cfg->stack_inbalance_var->dreg;
2596                 MONO_ADD_INS (cfg->cbb, ins);
2597         }
2598
2599         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2600
2601         call->inst.sreg1 = addr->dreg;
2602
2603         if (imt_arg)
2604                 emit_imt_argument (cfg, call, NULL, imt_arg);
2605
2606         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2607
2608         if (check_sp) {
2609                 int sp_reg;
2610
2611                 sp_reg = mono_alloc_preg (cfg);
2612
2613                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2614                 ins->dreg = sp_reg;
2615                 MONO_ADD_INS (cfg->cbb, ins);
2616
2617                 /* Restore the stack so we don't crash when throwing the exception */
2618                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2619                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2620                 MONO_ADD_INS (cfg->cbb, ins);
2621
2622                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2623                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2624         }
2625
2626         if (rgctx_arg)
2627                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2628
2629         return (MonoInst*)call;
2630 }
2631
2632 static MonoInst*
2633 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2634
2635 static MonoInst*
2636 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2637 static MonoInst*
2638 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2639
2640 static MonoInst*
2641 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2642                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2643 {
2644 #ifndef DISABLE_REMOTING
2645         gboolean might_be_remote = FALSE;
2646 #endif
2647         gboolean virtual = this != NULL;
2648         gboolean enable_for_aot = TRUE;
2649         int context_used;
2650         MonoCallInst *call;
2651         int rgctx_reg = 0;
2652         gboolean need_unbox_trampoline;
2653
2654         if (!sig)
2655                 sig = mono_method_signature (method);
2656
2657         if (rgctx_arg) {
2658                 rgctx_reg = mono_alloc_preg (cfg);
2659                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2660         }
2661
2662         if (method->string_ctor) {
2663                 /* Create the real signature */
2664                 /* FIXME: Cache these */
2665                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2666                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2667
2668                 sig = ctor_sig;
2669         }
2670
2671         context_used = mini_method_check_context_used (cfg, method);
2672
2673 #ifndef DISABLE_REMOTING
2674         might_be_remote = this && sig->hasthis &&
2675                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2676                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2677
2678         if (might_be_remote && context_used) {
2679                 MonoInst *addr;
2680
2681                 g_assert (cfg->generic_sharing_context);
2682
2683                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2684
2685                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2686         }
2687 #endif
2688
2689         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2690
2691         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2692
2693 #ifndef DISABLE_REMOTING
2694         if (might_be_remote)
2695                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2696         else
2697 #endif
2698                 call->method = method;
2699         call->inst.flags |= MONO_INST_HAS_METHOD;
2700         call->inst.inst_left = this;
2701         call->tail_call = tail;
2702
2703         if (virtual) {
2704                 int vtable_reg, slot_reg, this_reg;
2705                 int offset;
2706
2707                 this_reg = this->dreg;
2708
2709                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2710                         MonoInst *dummy_use;
2711
2712                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2713
2714                         /* Make a call to delegate->invoke_impl */
2715                         call->inst.inst_basereg = this_reg;
2716                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2717                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2718
2719                         /* We must emit a dummy use here because the delegate trampoline will
2720                         replace the 'this' argument with the delegate target making this activation
2721                         no longer a root for the delegate.
2722                         This is an issue for delegates that target collectible code such as dynamic
2723                         methods of GC'able assemblies.
2724
2725                         For a test case look into #667921.
2726
2727                         FIXME: a dummy use is not the best way to do it as the local register allocator
2728                         will put it on a caller save register and spil it around the call. 
2729                         Ideally, we would either put it on a callee save register or only do the store part.  
2730                          */
2731                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2732
2733                         return (MonoInst*)call;
2734                 }
2735
2736                 if ((!cfg->compile_aot || enable_for_aot) && 
2737                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2738                          (MONO_METHOD_IS_FINAL (method) &&
2739                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2740                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2741                         /* 
2742                          * the method is not virtual, we just need to ensure this is not null
2743                          * and then we can call the method directly.
2744                          */
2745 #ifndef DISABLE_REMOTING
2746                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2747                                 /* 
2748                                  * The check above ensures method is not gshared, this is needed since
2749                                  * gshared methods can't have wrappers.
2750                                  */
2751                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2752                         }
2753 #endif
2754
2755                         if (!method->string_ctor)
2756                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2757
2758                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2759                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2760                         /*
2761                          * the method is virtual, but we can statically dispatch since either
2762                          * it's class or the method itself are sealed.
2763                          * But first we need to ensure it's not a null reference.
2764                          */
2765                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2766
2767                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2768                 } else {
2769                         vtable_reg = alloc_preg (cfg);
2770                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2771                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2772                                 slot_reg = -1;
2773 #ifdef MONO_ARCH_HAVE_IMT
2774                                 if (mono_use_imt) {
2775                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2776                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2777                                         slot_reg = vtable_reg;
2778                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2779                                 }
2780 #endif
2781                                 if (slot_reg == -1) {
2782                                         slot_reg = alloc_preg (cfg);
2783                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2784                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2785                                 }
2786                         } else {
2787                                 slot_reg = vtable_reg;
2788                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2789                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2790 #ifdef MONO_ARCH_HAVE_IMT
2791                                 if (imt_arg) {
2792                                         g_assert (mono_method_signature (method)->generic_param_count);
2793                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2794                                 }
2795 #endif
2796                         }
2797
2798                         call->inst.sreg1 = slot_reg;
2799                         call->inst.inst_offset = offset;
2800                         call->virtual = TRUE;
2801                 }
2802         }
2803
2804         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2805
2806         if (rgctx_arg)
2807                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2808
2809         return (MonoInst*)call;
2810 }
2811
2812 MonoInst*
2813 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2814 {
2815         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2816 }
2817
2818 MonoInst*
2819 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2820                                            MonoInst **args)
2821 {
2822         MonoCallInst *call;
2823
2824         g_assert (sig);
2825
2826         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2827         call->fptr = func;
2828
2829         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2830
2831         return (MonoInst*)call;
2832 }
2833
2834 MonoInst*
2835 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2836 {
2837         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2838
2839         g_assert (info);
2840
2841         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2842 }
2843
2844 /*
2845  * mono_emit_abs_call:
2846  *
2847  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2848  */
2849 inline static MonoInst*
2850 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2851                                         MonoMethodSignature *sig, MonoInst **args)
2852 {
2853         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2854         MonoInst *ins;
2855
2856         /* 
2857          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2858          * handle it.
2859          */
2860         if (cfg->abs_patches == NULL)
2861                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2862         g_hash_table_insert (cfg->abs_patches, ji, ji);
2863         ins = mono_emit_native_call (cfg, ji, sig, args);
2864         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2865         return ins;
2866 }
2867  
2868 static MonoInst*
2869 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2870 {
2871         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2872                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2873                         int widen_op = -1;
2874
2875                         /* 
2876                          * Native code might return non register sized integers 
2877                          * without initializing the upper bits.
2878                          */
2879                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2880                         case OP_LOADI1_MEMBASE:
2881                                 widen_op = OP_ICONV_TO_I1;
2882                                 break;
2883                         case OP_LOADU1_MEMBASE:
2884                                 widen_op = OP_ICONV_TO_U1;
2885                                 break;
2886                         case OP_LOADI2_MEMBASE:
2887                                 widen_op = OP_ICONV_TO_I2;
2888                                 break;
2889                         case OP_LOADU2_MEMBASE:
2890                                 widen_op = OP_ICONV_TO_U2;
2891                                 break;
2892                         default:
2893                                 break;
2894                         }
2895
2896                         if (widen_op != -1) {
2897                                 int dreg = alloc_preg (cfg);
2898                                 MonoInst *widen;
2899
2900                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2901                                 widen->type = ins->type;
2902                                 ins = widen;
2903                         }
2904                 }
2905         }
2906
2907         return ins;
2908 }
2909
2910 static MonoMethod*
2911 get_memcpy_method (void)
2912 {
2913         static MonoMethod *memcpy_method = NULL;
2914         if (!memcpy_method) {
2915                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2916                 if (!memcpy_method)
2917                         g_error ("Old corlib found. Install a new one");
2918         }
2919         return memcpy_method;
2920 }
2921
2922 static void
2923 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2924 {
2925         MonoClassField *field;
2926         gpointer iter = NULL;
2927
2928         while ((field = mono_class_get_fields (klass, &iter))) {
2929                 int foffset;
2930
2931                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2932                         continue;
2933                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2934                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2935                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2936                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2937                 } else {
2938                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2939                         if (field_class->has_references)
2940                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2941                 }
2942         }
2943 }
2944
2945 static void
2946 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2947 {
2948         int card_table_shift_bits;
2949         gpointer card_table_mask;
2950         guint8 *card_table;
2951         MonoInst *dummy_use;
2952         int nursery_shift_bits;
2953         size_t nursery_size;
2954         gboolean has_card_table_wb = FALSE;
2955
2956         if (!cfg->gen_write_barriers)
2957                 return;
2958
2959         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2960
2961         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2962
2963 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2964         has_card_table_wb = TRUE;
2965 #endif
2966
2967         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2968                 MonoInst *wbarrier;
2969
2970                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2971                 wbarrier->sreg1 = ptr->dreg;
2972                 wbarrier->sreg2 = value->dreg;
2973                 MONO_ADD_INS (cfg->cbb, wbarrier);
2974         } else if (card_table) {
2975                 int offset_reg = alloc_preg (cfg);
2976                 int card_reg  = alloc_preg (cfg);
2977                 MonoInst *ins;
2978
2979                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2980                 if (card_table_mask)
2981                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2982
2983                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2984                  * IMM's larger than 32bits.
2985                  */
2986                 if (cfg->compile_aot) {
2987                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2988                 } else {
2989                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2990                         ins->inst_p0 = card_table;
2991                         ins->dreg = card_reg;
2992                         MONO_ADD_INS (cfg->cbb, ins);
2993                 }
2994
2995                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2996                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2997         } else {
2998                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2999                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3000         }
3001
3002         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3003 }
3004
3005 static gboolean
3006 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3007 {
3008         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3009         unsigned need_wb = 0;
3010
3011         if (align == 0)
3012                 align = 4;
3013
3014         /*types with references can't have alignment smaller than sizeof(void*) */
3015         if (align < SIZEOF_VOID_P)
3016                 return FALSE;
3017
3018         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3019         if (size > 32 * SIZEOF_VOID_P)
3020                 return FALSE;
3021
3022         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3023
3024         /* We don't unroll more than 5 stores to avoid code bloat. */
3025         if (size > 5 * SIZEOF_VOID_P) {
3026                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3027                 size += (SIZEOF_VOID_P - 1);
3028                 size &= ~(SIZEOF_VOID_P - 1);
3029
3030                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3031                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3032                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3033                 return TRUE;
3034         }
3035
3036         destreg = iargs [0]->dreg;
3037         srcreg = iargs [1]->dreg;
3038         offset = 0;
3039
3040         dest_ptr_reg = alloc_preg (cfg);
3041         tmp_reg = alloc_preg (cfg);
3042
3043         /*tmp = dreg*/
3044         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3045
3046         while (size >= SIZEOF_VOID_P) {
3047                 MonoInst *load_inst;
3048                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3049                 load_inst->dreg = tmp_reg;
3050                 load_inst->inst_basereg = srcreg;
3051                 load_inst->inst_offset = offset;
3052                 MONO_ADD_INS (cfg->cbb, load_inst);
3053
3054                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3055
3056                 if (need_wb & 0x1)
3057                         emit_write_barrier (cfg, iargs [0], load_inst);
3058
3059                 offset += SIZEOF_VOID_P;
3060                 size -= SIZEOF_VOID_P;
3061                 need_wb >>= 1;
3062
3063                 /*tmp += sizeof (void*)*/
3064                 if (size >= SIZEOF_VOID_P) {
3065                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3066                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3067                 }
3068         }
3069
3070         /* Those cannot be references since size < sizeof (void*) */
3071         while (size >= 4) {
3072                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3073                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3074                 offset += 4;
3075                 size -= 4;
3076         }
3077
3078         while (size >= 2) {
3079                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3080                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3081                 offset += 2;
3082                 size -= 2;
3083         }
3084
3085         while (size >= 1) {
3086                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3087                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3088                 offset += 1;
3089                 size -= 1;
3090         }
3091
3092         return TRUE;
3093 }
3094
3095 /*
3096  * Emit code to copy a valuetype of type @klass whose address is stored in
3097  * @src->dreg to memory whose address is stored at @dest->dreg.
3098  */
3099 void
3100 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3101 {
3102         MonoInst *iargs [4];
3103         int context_used, n;
3104         guint32 align = 0;
3105         MonoMethod *memcpy_method;
3106         MonoInst *size_ins = NULL;
3107         MonoInst *memcpy_ins = NULL;
3108
3109         g_assert (klass);
3110         /*
3111          * This check breaks with spilled vars... need to handle it during verification anyway.
3112          * g_assert (klass && klass == src->klass && klass == dest->klass);
3113          */
3114
3115         if (mini_is_gsharedvt_klass (cfg, klass)) {
3116                 g_assert (!native);
3117                 context_used = mini_class_check_context_used (cfg, klass);
3118                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3119                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3120         }
3121
3122         if (native)
3123                 n = mono_class_native_size (klass, &align);
3124         else
3125                 n = mono_class_value_size (klass, &align);
3126
3127         /* if native is true there should be no references in the struct */
3128         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3129                 /* Avoid barriers when storing to the stack */
3130                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3131                           (dest->opcode == OP_LDADDR))) {
3132                         int context_used;
3133
3134                         iargs [0] = dest;
3135                         iargs [1] = src;
3136
3137                         context_used = mini_class_check_context_used (cfg, klass);
3138
3139                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3140                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3141                                 return;
3142                         } else if (context_used) {
3143                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3144                         }  else {
3145                                 if (cfg->compile_aot) {
3146                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3147                                 } else {
3148                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3149                                         mono_class_compute_gc_descriptor (klass);
3150                                 }
3151                         }
3152
3153                         if (size_ins)
3154                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3155                         else
3156                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3157                         return;
3158                 }
3159         }
3160
3161         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3162                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3163                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3164         } else {
3165                 iargs [0] = dest;
3166                 iargs [1] = src;
3167                 if (size_ins)
3168                         iargs [2] = size_ins;
3169                 else
3170                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3171                 
3172                 memcpy_method = get_memcpy_method ();
3173                 if (memcpy_ins)
3174                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3175                 else
3176                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3177         }
3178 }
3179
3180 static MonoMethod*
3181 get_memset_method (void)
3182 {
3183         static MonoMethod *memset_method = NULL;
3184         if (!memset_method) {
3185                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3186                 if (!memset_method)
3187                         g_error ("Old corlib found. Install a new one");
3188         }
3189         return memset_method;
3190 }
3191
3192 void
3193 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3194 {
3195         MonoInst *iargs [3];
3196         int n, context_used;
3197         guint32 align;
3198         MonoMethod *memset_method;
3199         MonoInst *size_ins = NULL;
3200         MonoInst *bzero_ins = NULL;
3201         static MonoMethod *bzero_method;
3202
3203         /* FIXME: Optimize this for the case when dest is an LDADDR */
3204
3205         mono_class_init (klass);
3206         if (mini_is_gsharedvt_klass (cfg, klass)) {
3207                 context_used = mini_class_check_context_used (cfg, klass);
3208                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3209                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3210                 if (!bzero_method)
3211                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3212                 g_assert (bzero_method);
3213                 iargs [0] = dest;
3214                 iargs [1] = size_ins;
3215                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3216                 return;
3217         }
3218
3219         n = mono_class_value_size (klass, &align);
3220
3221         if (n <= sizeof (gpointer) * 5) {
3222                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3223         }
3224         else {
3225                 memset_method = get_memset_method ();
3226                 iargs [0] = dest;
3227                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3228                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3229                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3230         }
3231 }
3232
3233 static MonoInst*
3234 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3235 {
3236         MonoInst *this = NULL;
3237
3238         g_assert (cfg->generic_sharing_context);
3239
3240         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3241                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3242                         !method->klass->valuetype)
3243                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3244
3245         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3246                 MonoInst *mrgctx_loc, *mrgctx_var;
3247
3248                 g_assert (!this);
3249                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3250
3251                 mrgctx_loc = mono_get_vtable_var (cfg);
3252                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3253
3254                 return mrgctx_var;
3255         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3256                 MonoInst *vtable_loc, *vtable_var;
3257
3258                 g_assert (!this);
3259
3260                 vtable_loc = mono_get_vtable_var (cfg);
3261                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3262
3263                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3264                         MonoInst *mrgctx_var = vtable_var;
3265                         int vtable_reg;
3266
3267                         vtable_reg = alloc_preg (cfg);
3268                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3269                         vtable_var->type = STACK_PTR;
3270                 }
3271
3272                 return vtable_var;
3273         } else {
3274                 MonoInst *ins;
3275                 int vtable_reg;
3276         
3277                 vtable_reg = alloc_preg (cfg);
3278                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3279                 return ins;
3280         }
3281 }
3282
3283 static MonoJumpInfoRgctxEntry *
3284 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3285 {
3286         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3287         res->method = method;
3288         res->in_mrgctx = in_mrgctx;
3289         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3290         res->data->type = patch_type;
3291         res->data->data.target = patch_data;
3292         res->info_type = info_type;
3293
3294         return res;
3295 }
3296
3297 static inline MonoInst*
3298 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3299 {
3300         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3301 }
3302
3303 static MonoInst*
3304 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3305                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3306 {
3307         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);
3308         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3309
3310         return emit_rgctx_fetch (cfg, rgctx, entry);
3311 }
3312
3313 static MonoInst*
3314 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3315                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3316 {
3317         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);
3318         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3319
3320         return emit_rgctx_fetch (cfg, rgctx, entry);
3321 }
3322
3323 static MonoInst*
3324 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3325                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3326 {
3327         MonoJumpInfoGSharedVtCall *call_info;
3328         MonoJumpInfoRgctxEntry *entry;
3329         MonoInst *rgctx;
3330
3331         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3332         call_info->sig = sig;
3333         call_info->method = cmethod;
3334
3335         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);
3336         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_gsharedvt_method (MonoCompile *cfg, int context_used,
3344                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3345 {
3346         MonoJumpInfoRgctxEntry *entry;
3347         MonoInst *rgctx;
3348
3349         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);
3350         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3351
3352         return emit_rgctx_fetch (cfg, rgctx, entry);
3353 }
3354
3355 /*
3356  * emit_get_rgctx_method:
3357  *
3358  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3359  * normal constants, else emit a load from the rgctx.
3360  */
3361 static MonoInst*
3362 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3363                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3364 {
3365         if (!context_used) {
3366                 MonoInst *ins;
3367
3368                 switch (rgctx_type) {
3369                 case MONO_RGCTX_INFO_METHOD:
3370                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3371                         return ins;
3372                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3373                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3374                         return ins;
3375                 default:
3376                         g_assert_not_reached ();
3377                 }
3378         } else {
3379                 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);
3380                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3381
3382                 return emit_rgctx_fetch (cfg, rgctx, entry);
3383         }
3384 }
3385
3386 static MonoInst*
3387 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3388                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3389 {
3390         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);
3391         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3392
3393         return emit_rgctx_fetch (cfg, rgctx, entry);
3394 }
3395
3396 static int
3397 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3398 {
3399         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3400         MonoRuntimeGenericContextInfoTemplate *template;
3401         int i, idx;
3402
3403         g_assert (info);
3404
3405         for (i = 0; i < info->num_entries; ++i) {
3406                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3407
3408                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3409                         return i;
3410         }
3411
3412         if (info->num_entries == info->count_entries) {
3413                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3414                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3415
3416                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3417
3418                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3419                 info->entries = new_entries;
3420                 info->count_entries = new_count_entries;
3421         }
3422
3423         idx = info->num_entries;
3424         template = &info->entries [idx];
3425         template->info_type = rgctx_type;
3426         template->data = data;
3427
3428         info->num_entries ++;
3429
3430         return idx;
3431 }
3432
3433 /*
3434  * emit_get_gsharedvt_info:
3435  *
3436  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3437  */
3438 static MonoInst*
3439 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3440 {
3441         MonoInst *ins;
3442         int idx, dreg;
3443
3444         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3445         /* Load info->entries [idx] */
3446         dreg = alloc_preg (cfg);
3447         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3448
3449         return ins;
3450 }
3451
3452 static MonoInst*
3453 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3454 {
3455         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3456 }
3457
3458 /*
3459  * On return the caller must check @klass for load errors.
3460  */
3461 static void
3462 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3463 {
3464         MonoInst *vtable_arg;
3465         MonoCallInst *call;
3466         int context_used;
3467
3468         context_used = mini_class_check_context_used (cfg, klass);
3469
3470         if (context_used) {
3471                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3472                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3473         } else {
3474                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3475
3476                 if (!vtable)
3477                         return;
3478                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3479         }
3480
3481         if (COMPILE_LLVM (cfg))
3482                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3483         else
3484                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3485 #ifdef MONO_ARCH_VTABLE_REG
3486         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3487         cfg->uses_vtable_reg = TRUE;
3488 #else
3489         NOT_IMPLEMENTED;
3490 #endif
3491 }
3492
3493 static void
3494 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3495 {
3496         MonoInst *ins;
3497
3498         if (cfg->gen_seq_points && cfg->method == method) {
3499                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3500                 if (nonempty_stack)
3501                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3502                 MONO_ADD_INS (cfg->cbb, ins);
3503         }
3504 }
3505
3506 static void
3507 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3508 {
3509         if (mini_get_debug_options ()->better_cast_details) {
3510                 int to_klass_reg = alloc_preg (cfg);
3511                 int vtable_reg = alloc_preg (cfg);
3512                 int klass_reg = alloc_preg (cfg);
3513                 MonoBasicBlock *is_null_bb = NULL;
3514                 MonoInst *tls_get;
3515
3516                 if (null_check) {
3517                         NEW_BBLOCK (cfg, is_null_bb);
3518
3519                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3520                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3521                 }
3522
3523                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3524                 if (!tls_get) {
3525                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3526                         exit (1);
3527                 }
3528
3529                 MONO_ADD_INS (cfg->cbb, tls_get);
3530                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3531                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3532
3533                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3534                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3535                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3536
3537                 if (null_check) {
3538                         MONO_START_BB (cfg, is_null_bb);
3539                         if (out_bblock)
3540                                 *out_bblock = cfg->cbb;
3541                 }
3542         }
3543 }
3544
3545 static void
3546 reset_cast_details (MonoCompile *cfg)
3547 {
3548         /* Reset the variables holding the cast details */
3549         if (mini_get_debug_options ()->better_cast_details) {
3550                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3551
3552                 MONO_ADD_INS (cfg->cbb, tls_get);
3553                 /* It is enough to reset the from field */
3554                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3555         }
3556 }
3557
3558 /*
3559  * On return the caller must check @array_class for load errors
3560  */
3561 static void
3562 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3563 {
3564         int vtable_reg = alloc_preg (cfg);
3565         int context_used;
3566
3567         context_used = mini_class_check_context_used (cfg, array_class);
3568
3569         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3570
3571         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3572
3573         if (cfg->opt & MONO_OPT_SHARED) {
3574                 int class_reg = alloc_preg (cfg);
3575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3576                 if (cfg->compile_aot) {
3577                         int klass_reg = alloc_preg (cfg);
3578                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3579                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3580                 } else {
3581                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3582                 }
3583         } else if (context_used) {
3584                 MonoInst *vtable_ins;
3585
3586                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3587                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3588         } else {
3589                 if (cfg->compile_aot) {
3590                         int vt_reg;
3591                         MonoVTable *vtable;
3592
3593                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3594                                 return;
3595                         vt_reg = alloc_preg (cfg);
3596                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3597                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3598                 } else {
3599                         MonoVTable *vtable;
3600                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3601                                 return;
3602                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3603                 }
3604         }
3605         
3606         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3607
3608         reset_cast_details (cfg);
3609 }
3610
3611 /**
3612  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3613  * generic code is generated.
3614  */
3615 static MonoInst*
3616 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3617 {
3618         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3619
3620         if (context_used) {
3621                 MonoInst *rgctx, *addr;
3622
3623                 /* FIXME: What if the class is shared?  We might not
3624                    have to get the address of the method from the
3625                    RGCTX. */
3626                 addr = emit_get_rgctx_method (cfg, context_used, method,
3627                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3628
3629                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3630
3631                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3632         } else {
3633                 gboolean pass_vtable, pass_mrgctx;
3634                 MonoInst *rgctx_arg = NULL;
3635
3636                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3637                 g_assert (!pass_mrgctx);
3638
3639                 if (pass_vtable) {
3640                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3641
3642                         g_assert (vtable);
3643                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3644                 }
3645
3646                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3647         }
3648 }
3649
3650 static MonoInst*
3651 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3652 {
3653         MonoInst *add;
3654         int obj_reg;
3655         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3656         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3657         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3658         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3659
3660         obj_reg = sp [0]->dreg;
3661         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3662         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3663
3664         /* FIXME: generics */
3665         g_assert (klass->rank == 0);
3666                         
3667         // Check rank == 0
3668         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3669         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3670
3671         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3672         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3673
3674         if (context_used) {
3675                 MonoInst *element_class;
3676
3677                 /* This assertion is from the unboxcast insn */
3678                 g_assert (klass->rank == 0);
3679
3680                 element_class = emit_get_rgctx_klass (cfg, context_used,
3681                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3682
3683                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3684                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3685         } else {
3686                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3687                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3688                 reset_cast_details (cfg);
3689         }
3690
3691         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3692         MONO_ADD_INS (cfg->cbb, add);
3693         add->type = STACK_MP;
3694         add->klass = klass;
3695
3696         return add;
3697 }
3698
3699 static MonoInst*
3700 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3701 {
3702         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3703         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3704         MonoInst *ins;
3705         int dreg, addr_reg;
3706
3707         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3708
3709         /* obj */
3710         args [0] = obj;
3711
3712         /* klass */
3713         args [1] = klass_inst;
3714
3715         /* CASTCLASS */
3716         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3717
3718         NEW_BBLOCK (cfg, is_ref_bb);
3719         NEW_BBLOCK (cfg, is_nullable_bb);
3720         NEW_BBLOCK (cfg, end_bb);
3721         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3722         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3723         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3724
3725         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3726         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3727
3728         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3729         addr_reg = alloc_dreg (cfg, STACK_MP);
3730
3731         /* Non-ref case */
3732         /* UNBOX */
3733         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3734         MONO_ADD_INS (cfg->cbb, addr);
3735
3736         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3737
3738         /* Ref case */
3739         MONO_START_BB (cfg, is_ref_bb);
3740
3741         /* Save the ref to a temporary */
3742         dreg = alloc_ireg (cfg);
3743         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3744         addr->dreg = addr_reg;
3745         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3746         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3747
3748         /* Nullable case */
3749         MONO_START_BB (cfg, is_nullable_bb);
3750
3751         {
3752                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3753                 MonoInst *unbox_call;
3754                 MonoMethodSignature *unbox_sig;
3755                 MonoInst *var;
3756
3757                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3758
3759                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3760                 unbox_sig->ret = &klass->byval_arg;
3761                 unbox_sig->param_count = 1;
3762                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3763                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3764
3765                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3766                 addr->dreg = addr_reg;
3767         }
3768
3769         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3770
3771         /* End */
3772         MONO_START_BB (cfg, end_bb);
3773
3774         /* LDOBJ */
3775         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3776
3777         *out_cbb = cfg->cbb;
3778
3779         return ins;
3780 }
3781
3782 /*
3783  * Returns NULL and set the cfg exception on error.
3784  */
3785 static MonoInst*
3786 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3787 {
3788         MonoInst *iargs [2];
3789         void *alloc_ftn;
3790
3791         if (context_used) {
3792                 MonoInst *data;
3793                 int rgctx_info;
3794                 MonoInst *iargs [2];
3795
3796                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3797
3798                 if (cfg->opt & MONO_OPT_SHARED)
3799                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3800                 else
3801                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3802                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3803
3804                 if (cfg->opt & MONO_OPT_SHARED) {
3805                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3806                         iargs [1] = data;
3807                         alloc_ftn = mono_object_new;
3808                 } else {
3809                         iargs [0] = data;
3810                         alloc_ftn = mono_object_new_specific;
3811                 }
3812
3813                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3814                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3815
3816                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3817         }
3818
3819         if (cfg->opt & MONO_OPT_SHARED) {
3820                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3821                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3822
3823                 alloc_ftn = mono_object_new;
3824         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3825                 /* This happens often in argument checking code, eg. throw new FooException... */
3826                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3827                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3828                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3829         } else {
3830                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3831                 MonoMethod *managed_alloc = NULL;
3832                 gboolean pass_lw;
3833
3834                 if (!vtable) {
3835                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3836                         cfg->exception_ptr = klass;
3837                         return NULL;
3838                 }
3839
3840 #ifndef MONO_CROSS_COMPILE
3841                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3842 #endif
3843
3844                 if (managed_alloc) {
3845                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3846                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3847                 }
3848                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3849                 if (pass_lw) {
3850                         guint32 lw = vtable->klass->instance_size;
3851                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3852                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3853                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3854                 }
3855                 else {
3856                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3857                 }
3858         }
3859
3860         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3861 }
3862         
3863 /*
3864  * Returns NULL and set the cfg exception on error.
3865  */     
3866 static MonoInst*
3867 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3868 {
3869         MonoInst *alloc, *ins;
3870
3871         *out_cbb = cfg->cbb;
3872
3873         if (mono_class_is_nullable (klass)) {
3874                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3875
3876                 if (context_used) {
3877                         /* FIXME: What if the class is shared?  We might not
3878                            have to get the method address from the RGCTX. */
3879                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3880                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3881                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3882
3883                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3884                 } else {
3885                         gboolean pass_vtable, pass_mrgctx;
3886                         MonoInst *rgctx_arg = NULL;
3887
3888                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3889                         g_assert (!pass_mrgctx);
3890
3891                         if (pass_vtable) {
3892                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3893
3894                                 g_assert (vtable);
3895                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3896                         }
3897
3898                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3899                 }
3900         }
3901
3902         if (mini_is_gsharedvt_klass (cfg, klass)) {
3903                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3904                 MonoInst *res, *is_ref, *src_var, *addr;
3905                 int addr_reg, dreg;
3906
3907                 dreg = alloc_ireg (cfg);
3908
3909                 NEW_BBLOCK (cfg, is_ref_bb);
3910                 NEW_BBLOCK (cfg, is_nullable_bb);
3911                 NEW_BBLOCK (cfg, end_bb);
3912                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3913                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3914                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3915
3916                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3917                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3918
3919                 /* Non-ref case */
3920                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3921                 if (!alloc)
3922                         return NULL;
3923                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3924                 ins->opcode = OP_STOREV_MEMBASE;
3925
3926                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3927                 res->type = STACK_OBJ;
3928                 res->klass = klass;
3929                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3930                 
3931                 /* Ref case */
3932                 MONO_START_BB (cfg, is_ref_bb);
3933                 addr_reg = alloc_ireg (cfg);
3934
3935                 /* val is a vtype, so has to load the value manually */
3936                 src_var = get_vreg_to_inst (cfg, val->dreg);
3937                 if (!src_var)
3938                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3939                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3940                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3941                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3942
3943                 /* Nullable case */
3944                 MONO_START_BB (cfg, is_nullable_bb);
3945
3946                 {
3947                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3948                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3949                         MonoInst *box_call;
3950                         MonoMethodSignature *box_sig;
3951
3952                         /*
3953                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3954                          * construct that method at JIT time, so have to do things by hand.
3955                          */
3956                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3957                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3958                         box_sig->param_count = 1;
3959                         box_sig->params [0] = &klass->byval_arg;
3960                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3961                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3962                         res->type = STACK_OBJ;
3963                         res->klass = klass;
3964                 }
3965
3966                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3967
3968                 MONO_START_BB (cfg, end_bb);
3969
3970                 *out_cbb = cfg->cbb;
3971
3972                 return res;
3973         } else {
3974                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3975                 if (!alloc)
3976                         return NULL;
3977
3978                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3979                 return alloc;
3980         }
3981 }
3982
3983
3984 static gboolean
3985 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3986 {
3987         int i;
3988         MonoGenericContainer *container;
3989         MonoGenericInst *ginst;
3990
3991         if (klass->generic_class) {
3992                 container = klass->generic_class->container_class->generic_container;
3993                 ginst = klass->generic_class->context.class_inst;
3994         } else if (klass->generic_container && context_used) {
3995                 container = klass->generic_container;
3996                 ginst = container->context.class_inst;
3997         } else {
3998                 return FALSE;
3999         }
4000
4001         for (i = 0; i < container->type_argc; ++i) {
4002                 MonoType *type;
4003                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4004                         continue;
4005                 type = ginst->type_argv [i];
4006                 if (mini_type_is_reference (cfg, type))
4007                         return TRUE;
4008         }
4009         return FALSE;
4010 }
4011
4012 // FIXME: This doesn't work yet (class libs tests fail?)
4013 #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)
4014
4015 static MonoInst*
4016 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4017 {
4018         MonoMethod *mono_castclass;
4019         MonoInst *res;
4020
4021         mono_castclass = mono_marshal_get_castclass_with_cache ();
4022
4023         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4024         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4025         reset_cast_details (cfg);
4026
4027         return res;
4028 }
4029
4030 /*
4031  * Returns NULL and set the cfg exception on error.
4032  */
4033 static MonoInst*
4034 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4035 {
4036         MonoBasicBlock *is_null_bb;
4037         int obj_reg = src->dreg;
4038         int vtable_reg = alloc_preg (cfg);
4039         MonoInst *klass_inst = NULL;
4040
4041         if (context_used) {
4042                 MonoInst *args [3];
4043
4044                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4045                         MonoInst *cache_ins;
4046
4047                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4048
4049                         /* obj */
4050                         args [0] = src;
4051
4052                         /* klass - it's the second element of the cache entry*/
4053                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4054
4055                         /* cache */
4056                         args [2] = cache_ins;
4057
4058                         return emit_castclass_with_cache (cfg, klass, args, NULL);
4059                 }
4060
4061                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4062         }
4063
4064         NEW_BBLOCK (cfg, is_null_bb);
4065
4066         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4067         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4068
4069         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4070
4071         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4072                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4073                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4074         } else {
4075                 int klass_reg = alloc_preg (cfg);
4076
4077                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4078
4079                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4080                         /* the remoting code is broken, access the class for now */
4081                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4082                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4083                                 if (!vt) {
4084                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4085                                         cfg->exception_ptr = klass;
4086                                         return NULL;
4087                                 }
4088                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4089                         } else {
4090                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4091                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4092                         }
4093                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4094                 } else {
4095                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4096                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4097                 }
4098         }
4099
4100         MONO_START_BB (cfg, is_null_bb);
4101
4102         reset_cast_details (cfg);
4103
4104         return src;
4105 }
4106
4107 /*
4108  * Returns NULL and set the cfg exception on error.
4109  */
4110 static MonoInst*
4111 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4112 {
4113         MonoInst *ins;
4114         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4115         int obj_reg = src->dreg;
4116         int vtable_reg = alloc_preg (cfg);
4117         int res_reg = alloc_ireg_ref (cfg);
4118         MonoInst *klass_inst = NULL;
4119
4120         if (context_used) {
4121                 MonoInst *args [3];
4122
4123                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4124                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4125                         MonoInst *cache_ins;
4126
4127                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4128
4129                         /* obj */
4130                         args [0] = src;
4131
4132                         /* klass - it's the second element of the cache entry*/
4133                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4134
4135                         /* cache */
4136                         args [2] = cache_ins;
4137
4138                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4139                 }
4140
4141                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4142         }
4143
4144         NEW_BBLOCK (cfg, is_null_bb);
4145         NEW_BBLOCK (cfg, false_bb);
4146         NEW_BBLOCK (cfg, end_bb);
4147
4148         /* Do the assignment at the beginning, so the other assignment can be if converted */
4149         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4150         ins->type = STACK_OBJ;
4151         ins->klass = klass;
4152
4153         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4154         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4155
4156         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4157
4158         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4159                 g_assert (!context_used);
4160                 /* the is_null_bb target simply copies the input register to the output */
4161                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4162         } else {
4163                 int klass_reg = alloc_preg (cfg);
4164
4165                 if (klass->rank) {
4166                         int rank_reg = alloc_preg (cfg);
4167                         int eclass_reg = alloc_preg (cfg);
4168
4169                         g_assert (!context_used);
4170                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4171                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4172                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4173                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4174                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4175                         if (klass->cast_class == mono_defaults.object_class) {
4176                                 int parent_reg = alloc_preg (cfg);
4177                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4178                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4179                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4180                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4181                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4182                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4183                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4184                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4185                         } else if (klass->cast_class == mono_defaults.enum_class) {
4186                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4187                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4188                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4189                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4190                         } else {
4191                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4192                                         /* Check that the object is a vector too */
4193                                         int bounds_reg = alloc_preg (cfg);
4194                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4195                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4196                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4197                                 }
4198
4199                                 /* the is_null_bb target simply copies the input register to the output */
4200                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4201                         }
4202                 } else if (mono_class_is_nullable (klass)) {
4203                         g_assert (!context_used);
4204                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4205                         /* the is_null_bb target simply copies the input register to the output */
4206                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4207                 } else {
4208                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4209                                 g_assert (!context_used);
4210                                 /* the remoting code is broken, access the class for now */
4211                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4212                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4213                                         if (!vt) {
4214                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4215                                                 cfg->exception_ptr = klass;
4216                                                 return NULL;
4217                                         }
4218                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4219                                 } else {
4220                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4221                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4222                                 }
4223                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4224                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4225                         } else {
4226                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4227                                 /* the is_null_bb target simply copies the input register to the output */
4228                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4229                         }
4230                 }
4231         }
4232
4233         MONO_START_BB (cfg, false_bb);
4234
4235         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4236         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4237
4238         MONO_START_BB (cfg, is_null_bb);
4239
4240         MONO_START_BB (cfg, end_bb);
4241
4242         return ins;
4243 }
4244
4245 static MonoInst*
4246 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4247 {
4248         /* This opcode takes as input an object reference and a class, and returns:
4249         0) if the object is an instance of the class,
4250         1) if the object is not instance of the class,
4251         2) if the object is a proxy whose type cannot be determined */
4252
4253         MonoInst *ins;
4254 #ifndef DISABLE_REMOTING
4255         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4256 #else
4257         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4258 #endif
4259         int obj_reg = src->dreg;
4260         int dreg = alloc_ireg (cfg);
4261         int tmp_reg;
4262 #ifndef DISABLE_REMOTING
4263         int klass_reg = alloc_preg (cfg);
4264 #endif
4265
4266         NEW_BBLOCK (cfg, true_bb);
4267         NEW_BBLOCK (cfg, false_bb);
4268         NEW_BBLOCK (cfg, end_bb);
4269 #ifndef DISABLE_REMOTING
4270         NEW_BBLOCK (cfg, false2_bb);
4271         NEW_BBLOCK (cfg, no_proxy_bb);
4272 #endif
4273
4274         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4275         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4276
4277         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4278 #ifndef DISABLE_REMOTING
4279                 NEW_BBLOCK (cfg, interface_fail_bb);
4280 #endif
4281
4282                 tmp_reg = alloc_preg (cfg);
4283                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4284 #ifndef DISABLE_REMOTING
4285                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4286                 MONO_START_BB (cfg, interface_fail_bb);
4287                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4288                 
4289                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4290
4291                 tmp_reg = alloc_preg (cfg);
4292                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4293                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4294                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4295 #else
4296                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4297 #endif
4298         } else {
4299 #ifndef DISABLE_REMOTING
4300                 tmp_reg = alloc_preg (cfg);
4301                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4302                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4303
4304                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4305                 tmp_reg = alloc_preg (cfg);
4306                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4307                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4308
4309                 tmp_reg = alloc_preg (cfg);             
4310                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4311                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4312                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4313                 
4314                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4315                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4316
4317                 MONO_START_BB (cfg, no_proxy_bb);
4318
4319                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4320 #else
4321                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4322 #endif
4323         }
4324
4325         MONO_START_BB (cfg, false_bb);
4326
4327         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4328         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4329
4330 #ifndef DISABLE_REMOTING
4331         MONO_START_BB (cfg, false2_bb);
4332
4333         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4334         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4335 #endif
4336
4337         MONO_START_BB (cfg, true_bb);
4338
4339         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4340
4341         MONO_START_BB (cfg, end_bb);
4342
4343         /* FIXME: */
4344         MONO_INST_NEW (cfg, ins, OP_ICONST);
4345         ins->dreg = dreg;
4346         ins->type = STACK_I4;
4347
4348         return ins;
4349 }
4350
4351 static MonoInst*
4352 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4353 {
4354         /* This opcode takes as input an object reference and a class, and returns:
4355         0) if the object is an instance of the class,
4356         1) if the object is a proxy whose type cannot be determined
4357         an InvalidCastException exception is thrown otherwhise*/
4358         
4359         MonoInst *ins;
4360 #ifndef DISABLE_REMOTING
4361         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4362 #else
4363         MonoBasicBlock *ok_result_bb;
4364 #endif
4365         int obj_reg = src->dreg;
4366         int dreg = alloc_ireg (cfg);
4367         int tmp_reg = alloc_preg (cfg);
4368
4369 #ifndef DISABLE_REMOTING
4370         int klass_reg = alloc_preg (cfg);
4371         NEW_BBLOCK (cfg, end_bb);
4372 #endif
4373
4374         NEW_BBLOCK (cfg, ok_result_bb);
4375
4376         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4377         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4378
4379         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4380
4381         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4382 #ifndef DISABLE_REMOTING
4383                 NEW_BBLOCK (cfg, interface_fail_bb);
4384         
4385                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4386                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4387                 MONO_START_BB (cfg, interface_fail_bb);
4388                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4389
4390                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4391
4392                 tmp_reg = alloc_preg (cfg);             
4393                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4394                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4395                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4396                 
4397                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4398                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4399 #else
4400                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4401                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4402                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4403 #endif
4404         } else {
4405 #ifndef DISABLE_REMOTING
4406                 NEW_BBLOCK (cfg, no_proxy_bb);
4407
4408                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4409                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4410                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4411
4412                 tmp_reg = alloc_preg (cfg);
4413                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4414                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4415
4416                 tmp_reg = alloc_preg (cfg);
4417                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4418                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4419                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4420
4421                 NEW_BBLOCK (cfg, fail_1_bb);
4422                 
4423                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4424
4425                 MONO_START_BB (cfg, fail_1_bb);
4426
4427                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4428                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4429
4430                 MONO_START_BB (cfg, no_proxy_bb);
4431
4432                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4433 #else
4434                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4435 #endif
4436         }
4437
4438         MONO_START_BB (cfg, ok_result_bb);
4439
4440         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4441
4442 #ifndef DISABLE_REMOTING
4443         MONO_START_BB (cfg, end_bb);
4444 #endif
4445
4446         /* FIXME: */
4447         MONO_INST_NEW (cfg, ins, OP_ICONST);
4448         ins->dreg = dreg;
4449         ins->type = STACK_I4;
4450
4451         return ins;
4452 }
4453
4454 /*
4455  * Returns NULL and set the cfg exception on error.
4456  */
4457 static G_GNUC_UNUSED MonoInst*
4458 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4459 {
4460         MonoInst *ptr;
4461         int dreg;
4462         gpointer *trampoline;
4463         MonoInst *obj, *method_ins, *tramp_ins;
4464         MonoDomain *domain;
4465         guint8 **code_slot;
4466
4467         obj = handle_alloc (cfg, klass, FALSE, 0);
4468         if (!obj)
4469                 return NULL;
4470
4471         /* Inline the contents of mono_delegate_ctor */
4472
4473         /* Set target field */
4474         /* Optimize away setting of NULL target */
4475         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4476                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4477                 if (cfg->gen_write_barriers) {
4478                         dreg = alloc_preg (cfg);
4479                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4480                         emit_write_barrier (cfg, ptr, target);
4481                 }
4482         }
4483
4484         /* Set method field */
4485         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4486         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4487         if (cfg->gen_write_barriers) {
4488                 dreg = alloc_preg (cfg);
4489                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4490                 emit_write_barrier (cfg, ptr, method_ins);
4491         }
4492         /* 
4493          * To avoid looking up the compiled code belonging to the target method
4494          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4495          * store it, and we fill it after the method has been compiled.
4496          */
4497         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4498                 MonoInst *code_slot_ins;
4499
4500                 if (context_used) {
4501                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4502                 } else {
4503                         domain = mono_domain_get ();
4504                         mono_domain_lock (domain);
4505                         if (!domain_jit_info (domain)->method_code_hash)
4506                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4507                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4508                         if (!code_slot) {
4509                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4510                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4511                         }
4512                         mono_domain_unlock (domain);
4513
4514                         if (cfg->compile_aot)
4515                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4516                         else
4517                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4518                 }
4519                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4520         }
4521
4522         /* Set invoke_impl field */
4523         if (cfg->compile_aot) {
4524                 MonoClassMethodPair *del_tramp;
4525
4526                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoClassMethodPair));
4527                 del_tramp->klass = klass;
4528                 del_tramp->method = context_used ? NULL : method;
4529                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4530         } else {
4531                 trampoline = mono_create_delegate_trampoline_with_method (cfg->domain, klass, context_used ? NULL : method);
4532                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4533         }
4534         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4535
4536         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4537
4538         return obj;
4539 }
4540
4541 static MonoInst*
4542 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4543 {
4544         MonoJitICallInfo *info;
4545
4546         /* Need to register the icall so it gets an icall wrapper */
4547         info = mono_get_array_new_va_icall (rank);
4548
4549         cfg->flags |= MONO_CFG_HAS_VARARGS;
4550
4551         /* mono_array_new_va () needs a vararg calling convention */
4552         cfg->disable_llvm = TRUE;
4553
4554         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4555         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4556 }
4557
4558 static void
4559 mono_emit_load_got_addr (MonoCompile *cfg)
4560 {
4561         MonoInst *getaddr, *dummy_use;
4562
4563         if (!cfg->got_var || cfg->got_var_allocated)
4564                 return;
4565
4566         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4567         getaddr->cil_code = cfg->header->code;
4568         getaddr->dreg = cfg->got_var->dreg;
4569
4570         /* Add it to the start of the first bblock */
4571         if (cfg->bb_entry->code) {
4572                 getaddr->next = cfg->bb_entry->code;
4573                 cfg->bb_entry->code = getaddr;
4574         }
4575         else
4576                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4577
4578         cfg->got_var_allocated = TRUE;
4579
4580         /* 
4581          * Add a dummy use to keep the got_var alive, since real uses might
4582          * only be generated by the back ends.
4583          * Add it to end_bblock, so the variable's lifetime covers the whole
4584          * method.
4585          * It would be better to make the usage of the got var explicit in all
4586          * cases when the backend needs it (i.e. calls, throw etc.), so this
4587          * wouldn't be needed.
4588          */
4589         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4590         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4591 }
4592
4593 static int inline_limit;
4594 static gboolean inline_limit_inited;
4595
4596 static gboolean
4597 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4598 {
4599         MonoMethodHeaderSummary header;
4600         MonoVTable *vtable;
4601 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4602         MonoMethodSignature *sig = mono_method_signature (method);
4603         int i;
4604 #endif
4605
4606         if (cfg->generic_sharing_context)
4607                 return FALSE;
4608
4609         if (cfg->inline_depth > 10)
4610                 return FALSE;
4611
4612 #ifdef MONO_ARCH_HAVE_LMF_OPS
4613         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4614                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4615             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4616                 return TRUE;
4617 #endif
4618
4619
4620         if (!mono_method_get_header_summary (method, &header))
4621                 return FALSE;
4622
4623         /*runtime, icall and pinvoke are checked by summary call*/
4624         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4625             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4626             (mono_class_is_marshalbyref (method->klass)) ||
4627             header.has_clauses)
4628                 return FALSE;
4629
4630         /* also consider num_locals? */
4631         /* Do the size check early to avoid creating vtables */
4632         if (!inline_limit_inited) {
4633                 if (g_getenv ("MONO_INLINELIMIT"))
4634                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4635                 else
4636                         inline_limit = INLINE_LENGTH_LIMIT;
4637                 inline_limit_inited = TRUE;
4638         }
4639         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4640                 return FALSE;
4641
4642         /*
4643          * if we can initialize the class of the method right away, we do,
4644          * otherwise we don't allow inlining if the class needs initialization,
4645          * since it would mean inserting a call to mono_runtime_class_init()
4646          * inside the inlined code
4647          */
4648         if (!(cfg->opt & MONO_OPT_SHARED)) {
4649                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4650                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4651                         vtable = mono_class_vtable (cfg->domain, method->klass);
4652                         if (!vtable)
4653                                 return FALSE;
4654                         if (!cfg->compile_aot)
4655                                 mono_runtime_class_init (vtable);
4656                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4657                         if (cfg->run_cctors && method->klass->has_cctor) {
4658                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4659                                 if (!method->klass->runtime_info)
4660                                         /* No vtable created yet */
4661                                         return FALSE;
4662                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4663                                 if (!vtable)
4664                                         return FALSE;
4665                                 /* This makes so that inline cannot trigger */
4666                                 /* .cctors: too many apps depend on them */
4667                                 /* running with a specific order... */
4668                                 if (! vtable->initialized)
4669                                         return FALSE;
4670                                 mono_runtime_class_init (vtable);
4671                         }
4672                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4673                         if (!method->klass->runtime_info)
4674                                 /* No vtable created yet */
4675                                 return FALSE;
4676                         vtable = mono_class_vtable (cfg->domain, method->klass);
4677                         if (!vtable)
4678                                 return FALSE;
4679                         if (!vtable->initialized)
4680                                 return FALSE;
4681                 }
4682         } else {
4683                 /* 
4684                  * If we're compiling for shared code
4685                  * the cctor will need to be run at aot method load time, for example,
4686                  * or at the end of the compilation of the inlining method.
4687                  */
4688                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4689                         return FALSE;
4690         }
4691
4692         /*
4693          * CAS - do not inline methods with declarative security
4694          * Note: this has to be before any possible return TRUE;
4695          */
4696         if (mono_security_method_has_declsec (method))
4697                 return FALSE;
4698
4699 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4700         if (mono_arch_is_soft_float ()) {
4701                 /* FIXME: */
4702                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4703                         return FALSE;
4704                 for (i = 0; i < sig->param_count; ++i)
4705                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4706                                 return FALSE;
4707         }
4708 #endif
4709
4710         return TRUE;
4711 }
4712
4713 static gboolean
4714 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4715 {
4716         if (!cfg->compile_aot) {
4717                 g_assert (vtable);
4718                 if (vtable->initialized)
4719                         return FALSE;
4720         }
4721
4722         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4723                 if (cfg->method == method)
4724                         return FALSE;
4725         }
4726
4727         if (!mono_class_needs_cctor_run (klass, method))
4728                 return FALSE;
4729
4730         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4731                 /* The initialization is already done before the method is called */
4732                 return FALSE;
4733
4734         return TRUE;
4735 }
4736
4737 static MonoInst*
4738 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4739 {
4740         MonoInst *ins;
4741         guint32 size;
4742         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4743         int context_used;
4744
4745         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4746                 size = -1;
4747         } else {
4748                 mono_class_init (klass);
4749                 size = mono_class_array_element_size (klass);
4750         }
4751
4752         mult_reg = alloc_preg (cfg);
4753         array_reg = arr->dreg;
4754         index_reg = index->dreg;
4755
4756 #if SIZEOF_REGISTER == 8
4757         /* The array reg is 64 bits but the index reg is only 32 */
4758         if (COMPILE_LLVM (cfg)) {
4759                 /* Not needed */
4760                 index2_reg = index_reg;
4761         } else {
4762                 index2_reg = alloc_preg (cfg);
4763                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4764         }
4765 #else
4766         if (index->type == STACK_I8) {
4767                 index2_reg = alloc_preg (cfg);
4768                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4769         } else {
4770                 index2_reg = index_reg;
4771         }
4772 #endif
4773
4774         if (bcheck)
4775                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4776
4777 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4778         if (size == 1 || size == 2 || size == 4 || size == 8) {
4779                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4780
4781                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4782                 ins->klass = mono_class_get_element_class (klass);
4783                 ins->type = STACK_MP;
4784
4785                 return ins;
4786         }
4787 #endif          
4788
4789         add_reg = alloc_ireg_mp (cfg);
4790
4791         if (size == -1) {
4792                 MonoInst *rgctx_ins;
4793
4794                 /* gsharedvt */
4795                 g_assert (cfg->generic_sharing_context);
4796                 context_used = mini_class_check_context_used (cfg, klass);
4797                 g_assert (context_used);
4798                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4799                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4800         } else {
4801                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4802         }
4803         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4804         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4805         ins->klass = mono_class_get_element_class (klass);
4806         ins->type = STACK_MP;
4807         MONO_ADD_INS (cfg->cbb, ins);
4808
4809         return ins;
4810 }
4811
4812 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4813 static MonoInst*
4814 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4815 {
4816         int bounds_reg = alloc_preg (cfg);
4817         int add_reg = alloc_ireg_mp (cfg);
4818         int mult_reg = alloc_preg (cfg);
4819         int mult2_reg = alloc_preg (cfg);
4820         int low1_reg = alloc_preg (cfg);
4821         int low2_reg = alloc_preg (cfg);
4822         int high1_reg = alloc_preg (cfg);
4823         int high2_reg = alloc_preg (cfg);
4824         int realidx1_reg = alloc_preg (cfg);
4825         int realidx2_reg = alloc_preg (cfg);
4826         int sum_reg = alloc_preg (cfg);
4827         int index1, index2, tmpreg;
4828         MonoInst *ins;
4829         guint32 size;
4830
4831         mono_class_init (klass);
4832         size = mono_class_array_element_size (klass);
4833
4834         index1 = index_ins1->dreg;
4835         index2 = index_ins2->dreg;
4836
4837 #if SIZEOF_REGISTER == 8
4838         /* The array reg is 64 bits but the index reg is only 32 */
4839         if (COMPILE_LLVM (cfg)) {
4840                 /* Not needed */
4841         } else {
4842                 tmpreg = alloc_preg (cfg);
4843                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4844                 index1 = tmpreg;
4845                 tmpreg = alloc_preg (cfg);
4846                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4847                 index2 = tmpreg;
4848         }
4849 #else
4850         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4851         tmpreg = -1;
4852 #endif
4853
4854         /* range checking */
4855         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4856                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4857
4858         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4859                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4860         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4861         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4862                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4863         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4864         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4865
4866         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4867                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4868         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4869         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4870                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4871         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4872         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4873
4874         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4875         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4876         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4877         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4878         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4879
4880         ins->type = STACK_MP;
4881         ins->klass = klass;
4882         MONO_ADD_INS (cfg->cbb, ins);
4883
4884         return ins;
4885 }
4886 #endif
4887
4888 static MonoInst*
4889 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4890 {
4891         int rank;
4892         MonoInst *addr;
4893         MonoMethod *addr_method;
4894         int element_size;
4895
4896         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4897
4898         if (rank == 1)
4899                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4900
4901 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4902         /* emit_ldelema_2 depends on OP_LMUL */
4903         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4904                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4905         }
4906 #endif
4907
4908         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4909         addr_method = mono_marshal_get_array_address (rank, element_size);
4910         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4911
4912         return addr;
4913 }
4914
4915 static MonoBreakPolicy
4916 always_insert_breakpoint (MonoMethod *method)
4917 {
4918         return MONO_BREAK_POLICY_ALWAYS;
4919 }
4920
4921 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4922
4923 /**
4924  * mono_set_break_policy:
4925  * policy_callback: the new callback function
4926  *
4927  * Allow embedders to decide wherther to actually obey breakpoint instructions
4928  * (both break IL instructions and Debugger.Break () method calls), for example
4929  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4930  * untrusted or semi-trusted code.
4931  *
4932  * @policy_callback will be called every time a break point instruction needs to
4933  * be inserted with the method argument being the method that calls Debugger.Break()
4934  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4935  * if it wants the breakpoint to not be effective in the given method.
4936  * #MONO_BREAK_POLICY_ALWAYS is the default.
4937  */
4938 void
4939 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4940 {
4941         if (policy_callback)
4942                 break_policy_func = policy_callback;
4943         else
4944                 break_policy_func = always_insert_breakpoint;
4945 }
4946
4947 static gboolean
4948 should_insert_brekpoint (MonoMethod *method) {
4949         switch (break_policy_func (method)) {
4950         case MONO_BREAK_POLICY_ALWAYS:
4951                 return TRUE;
4952         case MONO_BREAK_POLICY_NEVER:
4953                 return FALSE;
4954         case MONO_BREAK_POLICY_ON_DBG:
4955                 g_warning ("mdb no longer supported");
4956                 return FALSE;
4957         default:
4958                 g_warning ("Incorrect value returned from break policy callback");
4959                 return FALSE;
4960         }
4961 }
4962
4963 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4964 static MonoInst*
4965 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4966 {
4967         MonoInst *addr, *store, *load;
4968         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4969
4970         /* the bounds check is already done by the callers */
4971         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4972         if (is_set) {
4973                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4974                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4975                 if (mini_type_is_reference (cfg, fsig->params [2]))
4976                         emit_write_barrier (cfg, addr, load);
4977         } else {
4978                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4979                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4980         }
4981         return store;
4982 }
4983
4984
4985 static gboolean
4986 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4987 {
4988         return mini_type_is_reference (cfg, &klass->byval_arg);
4989 }
4990
4991 static MonoInst*
4992 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4993 {
4994         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4995                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
4996                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4997                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4998                 MonoInst *iargs [3];
4999
5000                 if (!helper->slot)
5001                         mono_class_setup_vtable (obj_array);
5002                 g_assert (helper->slot);
5003
5004                 if (sp [0]->type != STACK_OBJ)
5005                         return NULL;
5006                 if (sp [2]->type != STACK_OBJ)
5007                         return NULL;
5008
5009                 iargs [2] = sp [2];
5010                 iargs [1] = sp [1];
5011                 iargs [0] = sp [0];
5012
5013                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5014         } else {
5015                 MonoInst *ins;
5016
5017                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5018                         MonoInst *addr;
5019
5020                         // FIXME-VT: OP_ICONST optimization
5021                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5022                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5023                         ins->opcode = OP_STOREV_MEMBASE;
5024                 } else if (sp [1]->opcode == OP_ICONST) {
5025                         int array_reg = sp [0]->dreg;
5026                         int index_reg = sp [1]->dreg;
5027                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
5028
5029                         if (safety_checks)
5030                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5031                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5032                 } else {
5033                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5034                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5035                         if (generic_class_is_reference_type (cfg, klass))
5036                                 emit_write_barrier (cfg, addr, sp [2]);
5037                 }
5038                 return ins;
5039         }
5040 }
5041
5042 static MonoInst*
5043 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5044 {
5045         MonoClass *eklass;
5046         
5047         if (is_set)
5048                 eklass = mono_class_from_mono_type (fsig->params [2]);
5049         else
5050                 eklass = mono_class_from_mono_type (fsig->ret);
5051
5052
5053         if (is_set) {
5054                 return emit_array_store (cfg, eklass, args, FALSE);
5055         } else {
5056                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5057                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5058                 return ins;
5059         }
5060 }
5061
5062 static gboolean
5063 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5064 {
5065         uint32_t align;
5066
5067         //Only allow for valuetypes
5068         if (!param_klass->valuetype || !return_klass->valuetype)
5069                 return FALSE;
5070
5071         //That are blitable
5072         if (param_klass->has_references || return_klass->has_references)
5073                 return FALSE;
5074
5075         //And have the same size
5076         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5077                 return FALSE;
5078         return TRUE;
5079 }
5080
5081 static MonoInst*
5082 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5083 {
5084         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5085         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5086
5087         //Valuetypes that are semantically equivalent
5088         if (is_unsafe_mov_compatible (param_klass, return_klass))
5089                 return args [0];
5090
5091         //Arrays of valuetypes that are semantically equivalent
5092         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5093                 return args [0];
5094
5095         return NULL;
5096 }
5097
5098 static MonoInst*
5099 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5100 {
5101 #ifdef MONO_ARCH_SIMD_INTRINSICS
5102         MonoInst *ins = NULL;
5103
5104         if (cfg->opt & MONO_OPT_SIMD) {
5105                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5106                 if (ins)
5107                         return ins;
5108         }
5109 #endif
5110
5111         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5112 }
5113
5114 static MonoInst*
5115 emit_memory_barrier (MonoCompile *cfg, int kind)
5116 {
5117         MonoInst *ins = NULL;
5118         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5119         MONO_ADD_INS (cfg->cbb, ins);
5120         ins->backend.memory_barrier_kind = kind;
5121
5122         return ins;
5123 }
5124
5125 static MonoInst*
5126 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5127 {
5128         MonoInst *ins = NULL;
5129         int opcode = 0;
5130
5131         /* The LLVM backend supports these intrinsics */
5132         if (cmethod->klass == mono_defaults.math_class) {
5133                 if (strcmp (cmethod->name, "Sin") == 0) {
5134                         opcode = OP_SIN;
5135                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5136                         opcode = OP_COS;
5137                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5138                         opcode = OP_SQRT;
5139                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5140                         opcode = OP_ABS;
5141                 }
5142
5143                 if (opcode) {
5144                         MONO_INST_NEW (cfg, ins, opcode);
5145                         ins->type = STACK_R8;
5146                         ins->dreg = mono_alloc_freg (cfg);
5147                         ins->sreg1 = args [0]->dreg;
5148                         MONO_ADD_INS (cfg->cbb, ins);
5149                 }
5150
5151                 opcode = 0;
5152                 if (cfg->opt & MONO_OPT_CMOV) {
5153                         if (strcmp (cmethod->name, "Min") == 0) {
5154                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5155                                         opcode = OP_IMIN;
5156                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5157                                         opcode = OP_IMIN_UN;
5158                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5159                                         opcode = OP_LMIN;
5160                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5161                                         opcode = OP_LMIN_UN;
5162                         } else if (strcmp (cmethod->name, "Max") == 0) {
5163                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5164                                         opcode = OP_IMAX;
5165                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5166                                         opcode = OP_IMAX_UN;
5167                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5168                                         opcode = OP_LMAX;
5169                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5170                                         opcode = OP_LMAX_UN;
5171                         }
5172                 }
5173
5174                 if (opcode) {
5175                         MONO_INST_NEW (cfg, ins, opcode);
5176                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5177                         ins->dreg = mono_alloc_ireg (cfg);
5178                         ins->sreg1 = args [0]->dreg;
5179                         ins->sreg2 = args [1]->dreg;
5180                         MONO_ADD_INS (cfg->cbb, ins);
5181                 }
5182         }
5183
5184         return ins;
5185 }
5186
5187 static MonoInst*
5188 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5189 {
5190         if (cmethod->klass == mono_defaults.array_class) {
5191                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5192                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5193                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5194                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5195                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5196                         return emit_array_unsafe_mov (cfg, fsig, args);
5197         }
5198
5199         return NULL;
5200 }
5201
5202 static MonoInst*
5203 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5204 {
5205         MonoInst *ins = NULL;
5206         
5207         static MonoClass *runtime_helpers_class = NULL;
5208         if (! runtime_helpers_class)
5209                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5210                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5211
5212         if (cmethod->klass == mono_defaults.string_class) {
5213                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5214                         int dreg = alloc_ireg (cfg);
5215                         int index_reg = alloc_preg (cfg);
5216                         int mult_reg = alloc_preg (cfg);
5217                         int add_reg = alloc_preg (cfg);
5218
5219 #if SIZEOF_REGISTER == 8
5220                         /* The array reg is 64 bits but the index reg is only 32 */
5221                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5222 #else
5223                         index_reg = args [1]->dreg;
5224 #endif  
5225                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5226
5227 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5228                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5229                         add_reg = ins->dreg;
5230                         /* Avoid a warning */
5231                         mult_reg = 0;
5232                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5233                                                                    add_reg, 0);
5234 #else
5235                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5236                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5237                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5238                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5239 #endif
5240                         type_from_op (ins, NULL, NULL);
5241                         return ins;
5242                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5243                         int dreg = alloc_ireg (cfg);
5244                         /* Decompose later to allow more optimizations */
5245                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5246                         ins->type = STACK_I4;
5247                         ins->flags |= MONO_INST_FAULT;
5248                         cfg->cbb->has_array_access = TRUE;
5249                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5250
5251                         return ins;
5252                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5253                         int mult_reg = alloc_preg (cfg);
5254                         int add_reg = alloc_preg (cfg);
5255
5256                         /* The corlib functions check for oob already. */
5257                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5258                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5259                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5260                         return cfg->cbb->last_ins;
5261                 } else 
5262                         return NULL;
5263         } else if (cmethod->klass == mono_defaults.object_class) {
5264
5265                 if (strcmp (cmethod->name, "GetType") == 0) {
5266                         int dreg = alloc_ireg_ref (cfg);
5267                         int vt_reg = alloc_preg (cfg);
5268                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5269                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5270                         type_from_op (ins, NULL, NULL);
5271
5272                         return ins;
5273 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5274                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5275                         int dreg = alloc_ireg (cfg);
5276                         int t1 = alloc_ireg (cfg);
5277         
5278                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5279                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5280                         ins->type = STACK_I4;
5281
5282                         return ins;
5283 #endif
5284                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5285                         MONO_INST_NEW (cfg, ins, OP_NOP);
5286                         MONO_ADD_INS (cfg->cbb, ins);
5287                         return ins;
5288                 } else
5289                         return NULL;
5290         } else if (cmethod->klass == mono_defaults.array_class) {
5291                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5292                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5293
5294 #ifndef MONO_BIG_ARRAYS
5295                 /*
5296                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5297                  * Array methods.
5298                  */
5299                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5300                         int dreg = alloc_ireg (cfg);
5301                         int bounds_reg = alloc_ireg_mp (cfg);
5302                         MonoBasicBlock *end_bb, *szarray_bb;
5303                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5304
5305                         NEW_BBLOCK (cfg, end_bb);
5306                         NEW_BBLOCK (cfg, szarray_bb);
5307
5308                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5309                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5310                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5311                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5312                         /* Non-szarray case */
5313                         if (get_length)
5314                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5315                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5316                         else
5317                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5318                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5319                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5320                         MONO_START_BB (cfg, szarray_bb);
5321                         /* Szarray case */
5322                         if (get_length)
5323                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5324                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5325                         else
5326                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5327                         MONO_START_BB (cfg, end_bb);
5328
5329                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5330                         ins->type = STACK_I4;
5331                         
5332                         return ins;
5333                 }
5334 #endif
5335
5336                 if (cmethod->name [0] != 'g')
5337                         return NULL;
5338
5339                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5340                         int dreg = alloc_ireg (cfg);
5341                         int vtable_reg = alloc_preg (cfg);
5342                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5343                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5344                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5345                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5346                         type_from_op (ins, NULL, NULL);
5347
5348                         return ins;
5349                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5350                         int dreg = alloc_ireg (cfg);
5351
5352                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5353                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5354                         type_from_op (ins, NULL, NULL);
5355
5356                         return ins;
5357                 } else
5358                         return NULL;
5359         } else if (cmethod->klass == runtime_helpers_class) {
5360
5361                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5362                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5363                         return ins;
5364                 } else
5365                         return NULL;
5366         } else if (cmethod->klass == mono_defaults.thread_class) {
5367                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5368                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5369                         MONO_ADD_INS (cfg->cbb, ins);
5370                         return ins;
5371                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5372                         return emit_memory_barrier (cfg, FullBarrier);
5373                 }
5374         } else if (cmethod->klass == mono_defaults.monitor_class) {
5375
5376                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5377 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5378                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5379                         MonoMethod *fast_method = NULL;
5380
5381                         /* Avoid infinite recursion */
5382                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5383                                 return NULL;
5384                                 
5385                         fast_method = mono_monitor_get_fast_path (cmethod);
5386                         if (!fast_method)
5387                                 return NULL;
5388
5389                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5390                 }
5391 #endif
5392
5393 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5394                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5395                         MonoCallInst *call;
5396
5397                         if (COMPILE_LLVM (cfg)) {
5398                                 /* 
5399                                  * Pass the argument normally, the LLVM backend will handle the
5400                                  * calling convention problems.
5401                                  */
5402                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5403                         } else {
5404                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5405                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5406                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5407                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5408                         }
5409
5410                         return (MonoInst*)call;
5411                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5412                         MonoCallInst *call;
5413
5414                         if (COMPILE_LLVM (cfg)) {
5415                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5416                         } else {
5417                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5418                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5419                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5420                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5421                         }
5422
5423                         return (MonoInst*)call;
5424                 }
5425 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5426                 {
5427                 MonoMethod *fast_method = NULL;
5428
5429                 /* Avoid infinite recursion */
5430                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5431                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5432                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5433                         return NULL;
5434
5435                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5436                                 strcmp (cmethod->name, "Exit") == 0)
5437                         fast_method = mono_monitor_get_fast_path (cmethod);
5438                 if (!fast_method)
5439                         return NULL;
5440
5441                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5442                 }
5443 #endif
5444         } else if (cmethod->klass->image == mono_defaults.corlib &&
5445                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5446                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5447                 ins = NULL;
5448
5449 #if SIZEOF_REGISTER == 8
5450                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5451                         /* 64 bit reads are already atomic */
5452                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5453                         ins->dreg = mono_alloc_preg (cfg);
5454                         ins->inst_basereg = args [0]->dreg;
5455                         ins->inst_offset = 0;
5456                         MONO_ADD_INS (cfg->cbb, ins);
5457                 }
5458 #endif
5459
5460 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5461                 if (strcmp (cmethod->name, "Increment") == 0) {
5462                         MonoInst *ins_iconst;
5463                         guint32 opcode = 0;
5464
5465                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5466                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5467                                 cfg->has_atomic_add_new_i4 = TRUE;
5468                         }
5469 #if SIZEOF_REGISTER == 8
5470                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5471                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5472 #endif
5473                         if (opcode) {
5474                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5475                                 ins_iconst->inst_c0 = 1;
5476                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5477                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5478
5479                                 MONO_INST_NEW (cfg, ins, opcode);
5480                                 ins->dreg = mono_alloc_ireg (cfg);
5481                                 ins->inst_basereg = args [0]->dreg;
5482                                 ins->inst_offset = 0;
5483                                 ins->sreg2 = ins_iconst->dreg;
5484                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5485                                 MONO_ADD_INS (cfg->cbb, ins);
5486                         }
5487                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5488                         MonoInst *ins_iconst;
5489                         guint32 opcode = 0;
5490
5491                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5492                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5493                                 cfg->has_atomic_add_new_i4 = TRUE;
5494                         }
5495 #if SIZEOF_REGISTER == 8
5496                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5497                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5498 #endif
5499                         if (opcode) {
5500                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5501                                 ins_iconst->inst_c0 = -1;
5502                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5503                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5504
5505                                 MONO_INST_NEW (cfg, ins, opcode);
5506                                 ins->dreg = mono_alloc_ireg (cfg);
5507                                 ins->inst_basereg = args [0]->dreg;
5508                                 ins->inst_offset = 0;
5509                                 ins->sreg2 = ins_iconst->dreg;
5510                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5511                                 MONO_ADD_INS (cfg->cbb, ins);
5512                         }
5513                 } else if (strcmp (cmethod->name, "Add") == 0) {
5514                         guint32 opcode = 0;
5515
5516                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5517                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5518                                 cfg->has_atomic_add_new_i4 = TRUE;
5519                         }
5520 #if SIZEOF_REGISTER == 8
5521                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5522                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5523 #endif
5524
5525                         if (opcode) {
5526                                 MONO_INST_NEW (cfg, ins, opcode);
5527                                 ins->dreg = mono_alloc_ireg (cfg);
5528                                 ins->inst_basereg = args [0]->dreg;
5529                                 ins->inst_offset = 0;
5530                                 ins->sreg2 = args [1]->dreg;
5531                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5532                                 MONO_ADD_INS (cfg->cbb, ins);
5533                         }
5534                 }
5535 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5536
5537 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5538                 if (strcmp (cmethod->name, "Exchange") == 0) {
5539                         guint32 opcode;
5540                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5541
5542                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5543                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5544                                 cfg->has_atomic_exchange_i4 = TRUE;
5545                         }
5546 #if SIZEOF_REGISTER == 8
5547                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5548                                         (fsig->params [0]->type == MONO_TYPE_I))
5549                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5550 #else
5551                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5552                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5553                                 cfg->has_atomic_exchange_i4 = TRUE;
5554                         }
5555 #endif
5556                         else
5557                                 return NULL;
5558
5559                         MONO_INST_NEW (cfg, ins, opcode);
5560                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5561                         ins->inst_basereg = args [0]->dreg;
5562                         ins->inst_offset = 0;
5563                         ins->sreg2 = args [1]->dreg;
5564                         MONO_ADD_INS (cfg->cbb, ins);
5565
5566                         switch (fsig->params [0]->type) {
5567                         case MONO_TYPE_I4:
5568                                 ins->type = STACK_I4;
5569                                 break;
5570                         case MONO_TYPE_I8:
5571                         case MONO_TYPE_I:
5572                                 ins->type = STACK_I8;
5573                                 break;
5574                         case MONO_TYPE_OBJECT:
5575                                 ins->type = STACK_OBJ;
5576                                 break;
5577                         default:
5578                                 g_assert_not_reached ();
5579                         }
5580
5581                         if (cfg->gen_write_barriers && is_ref)
5582                                 emit_write_barrier (cfg, args [0], args [1]);
5583                 }
5584 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5585  
5586 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5587                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5588                         int size = 0;
5589                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5590                         if (fsig->params [1]->type == MONO_TYPE_I4)
5591                                 size = 4;
5592                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5593                                 size = sizeof (gpointer);
5594                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5595                                 size = 8;
5596                         if (size == 4) {
5597                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5598                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5599                                 ins->sreg1 = args [0]->dreg;
5600                                 ins->sreg2 = args [1]->dreg;
5601                                 ins->sreg3 = args [2]->dreg;
5602                                 ins->type = STACK_I4;
5603                                 MONO_ADD_INS (cfg->cbb, ins);
5604                         } else if (size == 8) {
5605                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5606                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5607                                 ins->sreg1 = args [0]->dreg;
5608                                 ins->sreg2 = args [1]->dreg;
5609                                 ins->sreg3 = args [2]->dreg;
5610                                 ins->type = STACK_I8;
5611                                 MONO_ADD_INS (cfg->cbb, ins);
5612                         } else {
5613                                 /* g_assert_not_reached (); */
5614                         }
5615                         if (cfg->gen_write_barriers && is_ref)
5616                                 emit_write_barrier (cfg, args [0], args [1]);
5617                 }
5618 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5619
5620                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5621                         ins = emit_memory_barrier (cfg, FullBarrier);
5622
5623                 if (ins)
5624                         return ins;
5625         } else if (cmethod->klass->image == mono_defaults.corlib) {
5626                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5627                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5628                         if (should_insert_brekpoint (cfg->method)) {
5629                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5630                         } else {
5631                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5632                                 MONO_ADD_INS (cfg->cbb, ins);
5633                         }
5634                         return ins;
5635                 }
5636                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5637                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5638 #ifdef TARGET_WIN32
5639                         EMIT_NEW_ICONST (cfg, ins, 1);
5640 #else
5641                         EMIT_NEW_ICONST (cfg, ins, 0);
5642 #endif
5643                         return ins;
5644                 }
5645         } else if (cmethod->klass == mono_defaults.math_class) {
5646                 /* 
5647                  * There is general branches code for Min/Max, but it does not work for 
5648                  * all inputs:
5649                  * http://everything2.com/?node_id=1051618
5650                  */
5651         } 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)) {
5652 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5653                 MonoInst *pi;
5654                 MonoJumpInfoToken *ji;
5655                 MonoString *s;
5656
5657                 cfg->disable_llvm = TRUE;
5658
5659                 if (args [0]->opcode == OP_GOT_ENTRY) {
5660                         pi = args [0]->inst_p1;
5661                         g_assert (pi->opcode == OP_PATCH_INFO);
5662                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5663                         ji = pi->inst_p0;
5664                 } else {
5665                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5666                         ji = args [0]->inst_p0;
5667                 }
5668
5669                 NULLIFY_INS (args [0]);
5670
5671                 // FIXME: Ugly
5672                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5673                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5674                 ins->dreg = mono_alloc_ireg (cfg);
5675                 // FIXME: Leaks
5676                 ins->inst_p0 = mono_string_to_utf8 (s);
5677                 MONO_ADD_INS (cfg->cbb, ins);
5678                 return ins;
5679 #endif
5680         }
5681
5682 #ifdef MONO_ARCH_SIMD_INTRINSICS
5683         if (cfg->opt & MONO_OPT_SIMD) {
5684                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5685                 if (ins)
5686                         return ins;
5687         }
5688 #endif
5689
5690         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5691         if (ins)
5692                 return ins;
5693
5694         if (COMPILE_LLVM (cfg)) {
5695                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5696                 if (ins)
5697                         return ins;
5698         }
5699
5700         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5701 }
5702
5703 /*
5704  * This entry point could be used later for arbitrary method
5705  * redirection.
5706  */
5707 inline static MonoInst*
5708 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5709                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5710 {
5711         if (method->klass == mono_defaults.string_class) {
5712                 /* managed string allocation support */
5713                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5714                         MonoInst *iargs [2];
5715                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5716                         MonoMethod *managed_alloc = NULL;
5717
5718                         g_assert (vtable); /*Should not fail since it System.String*/
5719 #ifndef MONO_CROSS_COMPILE
5720                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5721 #endif
5722                         if (!managed_alloc)
5723                                 return NULL;
5724                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5725                         iargs [1] = args [0];
5726                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5727                 }
5728         }
5729         return NULL;
5730 }
5731
5732 static void
5733 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5734 {
5735         MonoInst *store, *temp;
5736         int i;
5737
5738         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5739                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5740
5741                 /*
5742                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5743                  * would be different than the MonoInst's used to represent arguments, and
5744                  * the ldelema implementation can't deal with that.
5745                  * Solution: When ldelema is used on an inline argument, create a var for 
5746                  * it, emit ldelema on that var, and emit the saving code below in
5747                  * inline_method () if needed.
5748                  */
5749                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5750                 cfg->args [i] = temp;
5751                 /* This uses cfg->args [i] which is set by the preceeding line */
5752                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5753                 store->cil_code = sp [0]->cil_code;
5754                 sp++;
5755         }
5756 }
5757
5758 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5759 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5760
5761 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5762 static gboolean
5763 check_inline_called_method_name_limit (MonoMethod *called_method)
5764 {
5765         int strncmp_result;
5766         static const char *limit = NULL;
5767         
5768         if (limit == NULL) {
5769                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5770
5771                 if (limit_string != NULL)
5772                         limit = limit_string;
5773                 else
5774                         limit = "";
5775         }
5776
5777         if (limit [0] != '\0') {
5778                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5779
5780                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5781                 g_free (called_method_name);
5782         
5783                 //return (strncmp_result <= 0);
5784                 return (strncmp_result == 0);
5785         } else {
5786                 return TRUE;
5787         }
5788 }
5789 #endif
5790
5791 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5792 static gboolean
5793 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5794 {
5795         int strncmp_result;
5796         static const char *limit = NULL;
5797         
5798         if (limit == NULL) {
5799                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5800                 if (limit_string != NULL) {
5801                         limit = limit_string;
5802                 } else {
5803                         limit = "";
5804                 }
5805         }
5806
5807         if (limit [0] != '\0') {
5808                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5809
5810                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5811                 g_free (caller_method_name);
5812         
5813                 //return (strncmp_result <= 0);
5814                 return (strncmp_result == 0);
5815         } else {
5816                 return TRUE;
5817         }
5818 }
5819 #endif
5820
5821 static void
5822 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5823 {
5824         static double r8_0 = 0.0;
5825         MonoInst *ins;
5826         int t;
5827
5828         rtype = mini_replace_type (rtype);
5829         t = rtype->type;
5830
5831         if (rtype->byref) {
5832                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5833         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5834                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5835         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5836                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5837         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5838                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5839                 ins->type = STACK_R8;
5840                 ins->inst_p0 = (void*)&r8_0;
5841                 ins->dreg = dreg;
5842                 MONO_ADD_INS (cfg->cbb, ins);
5843         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5844                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5845                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5846         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5847                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5848         } else {
5849                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5850         }
5851 }
5852
5853 static void
5854 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5855 {
5856         int t;
5857
5858         rtype = mini_replace_type (rtype);
5859         t = rtype->type;
5860
5861         if (rtype->byref) {
5862                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
5863         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5864                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
5865         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5866                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
5867         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5868                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
5869         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5870                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5871                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5872         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5873                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5874         } else {
5875                 emit_init_rvar (cfg, dreg, rtype);
5876         }
5877 }
5878
5879 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
5880 static void
5881 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
5882 {
5883         MonoInst *var = cfg->locals [local];
5884         if (COMPILE_SOFT_FLOAT (cfg)) {
5885                 MonoInst *store;
5886                 int reg = alloc_dreg (cfg, var->type);
5887                 emit_init_rvar (cfg, reg, type);
5888                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5889         } else {
5890                 if (init)
5891                         emit_init_rvar (cfg, var->dreg, type);
5892                 else
5893                         emit_dummy_init_rvar (cfg, var->dreg, type);
5894         }
5895 }
5896
5897 static int
5898 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5899                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5900 {
5901         MonoInst *ins, *rvar = NULL;
5902         MonoMethodHeader *cheader;
5903         MonoBasicBlock *ebblock, *sbblock;
5904         int i, costs;
5905         MonoMethod *prev_inlined_method;
5906         MonoInst **prev_locals, **prev_args;
5907         MonoType **prev_arg_types;
5908         guint prev_real_offset;
5909         GHashTable *prev_cbb_hash;
5910         MonoBasicBlock **prev_cil_offset_to_bb;
5911         MonoBasicBlock *prev_cbb;
5912         unsigned char* prev_cil_start;
5913         guint32 prev_cil_offset_to_bb_len;
5914         MonoMethod *prev_current_method;
5915         MonoGenericContext *prev_generic_context;
5916         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5917
5918         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5919
5920 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5921         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5922                 return 0;
5923 #endif
5924 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5925         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5926                 return 0;
5927 #endif
5928
5929         if (cfg->verbose_level > 2)
5930                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5931
5932         if (!cmethod->inline_info) {
5933                 cfg->stat_inlineable_methods++;
5934                 cmethod->inline_info = 1;
5935         }
5936
5937         /* allocate local variables */
5938         cheader = mono_method_get_header (cmethod);
5939
5940         if (cheader == NULL || mono_loader_get_last_error ()) {
5941                 MonoLoaderError *error = mono_loader_get_last_error ();
5942
5943                 if (cheader)
5944                         mono_metadata_free_mh (cheader);
5945                 if (inline_always && error)
5946                         mono_cfg_set_exception (cfg, error->exception_type);
5947
5948                 mono_loader_clear_error ();
5949                 return 0;
5950         }
5951
5952         /*Must verify before creating locals as it can cause the JIT to assert.*/
5953         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5954                 mono_metadata_free_mh (cheader);
5955                 return 0;
5956         }
5957
5958         /* allocate space to store the return value */
5959         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5960                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5961         }
5962
5963         prev_locals = cfg->locals;
5964         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5965         for (i = 0; i < cheader->num_locals; ++i)
5966                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5967
5968         /* allocate start and end blocks */
5969         /* This is needed so if the inline is aborted, we can clean up */
5970         NEW_BBLOCK (cfg, sbblock);
5971         sbblock->real_offset = real_offset;
5972
5973         NEW_BBLOCK (cfg, ebblock);
5974         ebblock->block_num = cfg->num_bblocks++;
5975         ebblock->real_offset = real_offset;
5976
5977         prev_args = cfg->args;
5978         prev_arg_types = cfg->arg_types;
5979         prev_inlined_method = cfg->inlined_method;
5980         cfg->inlined_method = cmethod;
5981         cfg->ret_var_set = FALSE;
5982         cfg->inline_depth ++;
5983         prev_real_offset = cfg->real_offset;
5984         prev_cbb_hash = cfg->cbb_hash;
5985         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
5986         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
5987         prev_cil_start = cfg->cil_start;
5988         prev_cbb = cfg->cbb;
5989         prev_current_method = cfg->current_method;
5990         prev_generic_context = cfg->generic_context;
5991         prev_ret_var_set = cfg->ret_var_set;
5992
5993         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
5994                 virtual = TRUE;
5995
5996         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
5997
5998         ret_var_set = cfg->ret_var_set;
5999
6000         cfg->inlined_method = prev_inlined_method;
6001         cfg->real_offset = prev_real_offset;
6002         cfg->cbb_hash = prev_cbb_hash;
6003         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6004         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6005         cfg->cil_start = prev_cil_start;
6006         cfg->locals = prev_locals;
6007         cfg->args = prev_args;
6008         cfg->arg_types = prev_arg_types;
6009         cfg->current_method = prev_current_method;
6010         cfg->generic_context = prev_generic_context;
6011         cfg->ret_var_set = prev_ret_var_set;
6012         cfg->inline_depth --;
6013
6014         if ((costs >= 0 && costs < 60) || inline_always) {
6015                 if (cfg->verbose_level > 2)
6016                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6017                 
6018                 cfg->stat_inlined_methods++;
6019
6020                 /* always add some code to avoid block split failures */
6021                 MONO_INST_NEW (cfg, ins, OP_NOP);
6022                 MONO_ADD_INS (prev_cbb, ins);
6023
6024                 prev_cbb->next_bb = sbblock;
6025                 link_bblock (cfg, prev_cbb, sbblock);
6026
6027                 /* 
6028                  * Get rid of the begin and end bblocks if possible to aid local
6029                  * optimizations.
6030                  */
6031                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6032
6033                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6034                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6035
6036                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6037                         MonoBasicBlock *prev = ebblock->in_bb [0];
6038                         mono_merge_basic_blocks (cfg, prev, ebblock);
6039                         cfg->cbb = prev;
6040                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6041                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6042                                 cfg->cbb = prev_cbb;
6043                         }
6044                 } else {
6045                         /* 
6046                          * Its possible that the rvar is set in some prev bblock, but not in others.
6047                          * (#1835).
6048                          */
6049                         if (rvar) {
6050                                 MonoBasicBlock *bb;
6051
6052                                 for (i = 0; i < ebblock->in_count; ++i) {
6053                                         bb = ebblock->in_bb [i];
6054
6055                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6056                                                 cfg->cbb = bb;
6057
6058                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6059                                         }
6060                                 }
6061                         }
6062
6063                         cfg->cbb = ebblock;
6064                 }
6065
6066                 if (rvar) {
6067                         /*
6068                          * If the inlined method contains only a throw, then the ret var is not 
6069                          * set, so set it to a dummy value.
6070                          */
6071                         if (!ret_var_set)
6072                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6073
6074                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6075                         *sp++ = ins;
6076                 }
6077                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6078                 return costs + 1;
6079         } else {
6080                 if (cfg->verbose_level > 2)
6081                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6082                 cfg->exception_type = MONO_EXCEPTION_NONE;
6083                 mono_loader_clear_error ();
6084
6085                 /* This gets rid of the newly added bblocks */
6086                 cfg->cbb = prev_cbb;
6087         }
6088         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6089         return 0;
6090 }
6091
6092 /*
6093  * Some of these comments may well be out-of-date.
6094  * Design decisions: we do a single pass over the IL code (and we do bblock 
6095  * splitting/merging in the few cases when it's required: a back jump to an IL
6096  * address that was not already seen as bblock starting point).
6097  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6098  * Complex operations are decomposed in simpler ones right away. We need to let the 
6099  * arch-specific code peek and poke inside this process somehow (except when the 
6100  * optimizations can take advantage of the full semantic info of coarse opcodes).
6101  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6102  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6103  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6104  * opcode with value bigger than OP_LAST.
6105  * At this point the IR can be handed over to an interpreter, a dumb code generator
6106  * or to the optimizing code generator that will translate it to SSA form.
6107  *
6108  * Profiling directed optimizations.
6109  * We may compile by default with few or no optimizations and instrument the code
6110  * or the user may indicate what methods to optimize the most either in a config file
6111  * or through repeated runs where the compiler applies offline the optimizations to 
6112  * each method and then decides if it was worth it.
6113  */
6114
6115 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6116 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6117 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6118 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6119 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6120 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6121 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6122 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
6123
6124 /* offset from br.s -> br like opcodes */
6125 #define BIG_BRANCH_OFFSET 13
6126
6127 static gboolean
6128 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6129 {
6130         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6131
6132         return b == NULL || b == bb;
6133 }
6134
6135 static int
6136 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6137 {
6138         unsigned char *ip = start;
6139         unsigned char *target;
6140         int i;
6141         guint cli_addr;
6142         MonoBasicBlock *bblock;
6143         const MonoOpcode *opcode;
6144
6145         while (ip < end) {
6146                 cli_addr = ip - start;
6147                 i = mono_opcode_value ((const guint8 **)&ip, end);
6148                 if (i < 0)
6149                         UNVERIFIED;
6150                 opcode = &mono_opcodes [i];
6151                 switch (opcode->argument) {
6152                 case MonoInlineNone:
6153                         ip++; 
6154                         break;
6155                 case MonoInlineString:
6156                 case MonoInlineType:
6157                 case MonoInlineField:
6158                 case MonoInlineMethod:
6159                 case MonoInlineTok:
6160                 case MonoInlineSig:
6161                 case MonoShortInlineR:
6162                 case MonoInlineI:
6163                         ip += 5;
6164                         break;
6165                 case MonoInlineVar:
6166                         ip += 3;
6167                         break;
6168                 case MonoShortInlineVar:
6169                 case MonoShortInlineI:
6170                         ip += 2;
6171                         break;
6172                 case MonoShortInlineBrTarget:
6173                         target = start + cli_addr + 2 + (signed char)ip [1];
6174                         GET_BBLOCK (cfg, bblock, target);
6175                         ip += 2;
6176                         if (ip < end)
6177                                 GET_BBLOCK (cfg, bblock, ip);
6178                         break;
6179                 case MonoInlineBrTarget:
6180                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6181                         GET_BBLOCK (cfg, bblock, target);
6182                         ip += 5;
6183                         if (ip < end)
6184                                 GET_BBLOCK (cfg, bblock, ip);
6185                         break;
6186                 case MonoInlineSwitch: {
6187                         guint32 n = read32 (ip + 1);
6188                         guint32 j;
6189                         ip += 5;
6190                         cli_addr += 5 + 4 * n;
6191                         target = start + cli_addr;
6192                         GET_BBLOCK (cfg, bblock, target);
6193                         
6194                         for (j = 0; j < n; ++j) {
6195                                 target = start + cli_addr + (gint32)read32 (ip);
6196                                 GET_BBLOCK (cfg, bblock, target);
6197                                 ip += 4;
6198                         }
6199                         break;
6200                 }
6201                 case MonoInlineR:
6202                 case MonoInlineI8:
6203                         ip += 9;
6204                         break;
6205                 default:
6206                         g_assert_not_reached ();
6207                 }
6208
6209                 if (i == CEE_THROW) {
6210                         unsigned char *bb_start = ip - 1;
6211                         
6212                         /* Find the start of the bblock containing the throw */
6213                         bblock = NULL;
6214                         while ((bb_start >= start) && !bblock) {
6215                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6216                                 bb_start --;
6217                         }
6218                         if (bblock)
6219                                 bblock->out_of_line = 1;
6220                 }
6221         }
6222         return 0;
6223 unverified:
6224 exception_exit:
6225         *pos = ip;
6226         return 1;
6227 }
6228
6229 static inline MonoMethod *
6230 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6231 {
6232         MonoMethod *method;
6233
6234         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6235                 method = mono_method_get_wrapper_data (m, token);
6236                 if (context)
6237                         method = mono_class_inflate_generic_method (method, context);
6238         } else {
6239                 method = mono_get_method_full (m->klass->image, token, klass, context);
6240         }
6241
6242         return method;
6243 }
6244
6245 static inline MonoMethod *
6246 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6247 {
6248         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6249
6250         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6251                 return NULL;
6252
6253         return method;
6254 }
6255
6256 static inline MonoClass*
6257 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6258 {
6259         MonoClass *klass;
6260
6261         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6262                 klass = mono_method_get_wrapper_data (method, token);
6263                 if (context)
6264                         klass = mono_class_inflate_generic_class (klass, context);
6265         } else {
6266                 klass = mono_class_get_full (method->klass->image, token, context);
6267         }
6268         if (klass)
6269                 mono_class_init (klass);
6270         return klass;
6271 }
6272
6273 static inline MonoMethodSignature*
6274 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6275 {
6276         MonoMethodSignature *fsig;
6277
6278         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6279                 MonoError error;
6280
6281                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6282                 if (context) {
6283                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6284                         // FIXME:
6285                         g_assert (mono_error_ok (&error));
6286                 }
6287         } else {
6288                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6289         }
6290         return fsig;
6291 }
6292
6293 /*
6294  * Returns TRUE if the JIT should abort inlining because "callee"
6295  * is influenced by security attributes.
6296  */
6297 static
6298 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6299 {
6300         guint32 result;
6301         
6302         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6303                 return TRUE;
6304         }
6305         
6306         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6307         if (result == MONO_JIT_SECURITY_OK)
6308                 return FALSE;
6309
6310         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6311                 /* Generate code to throw a SecurityException before the actual call/link */
6312                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6313                 MonoInst *args [2];
6314
6315                 NEW_ICONST (cfg, args [0], 4);
6316                 NEW_METHODCONST (cfg, args [1], caller);
6317                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6318         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6319                  /* don't hide previous results */
6320                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6321                 cfg->exception_data = result;
6322                 return TRUE;
6323         }
6324         
6325         return FALSE;
6326 }
6327
6328 static MonoMethod*
6329 throw_exception (void)
6330 {
6331         static MonoMethod *method = NULL;
6332
6333         if (!method) {
6334                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6335                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6336         }
6337         g_assert (method);
6338         return method;
6339 }
6340
6341 static void
6342 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6343 {
6344         MonoMethod *thrower = throw_exception ();
6345         MonoInst *args [1];
6346
6347         EMIT_NEW_PCONST (cfg, args [0], ex);
6348         mono_emit_method_call (cfg, thrower, args, NULL);
6349 }
6350
6351 /*
6352  * Return the original method is a wrapper is specified. We can only access 
6353  * the custom attributes from the original method.
6354  */
6355 static MonoMethod*
6356 get_original_method (MonoMethod *method)
6357 {
6358         if (method->wrapper_type == MONO_WRAPPER_NONE)
6359                 return method;
6360
6361         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6362         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6363                 return NULL;
6364
6365         /* in other cases we need to find the original method */
6366         return mono_marshal_method_from_wrapper (method);
6367 }
6368
6369 static void
6370 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6371                                           MonoBasicBlock *bblock, unsigned char *ip)
6372 {
6373         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6374         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6375         if (ex)
6376                 emit_throw_exception (cfg, ex);
6377 }
6378
6379 static void
6380 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6381                                          MonoBasicBlock *bblock, unsigned char *ip)
6382 {
6383         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6384         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6385         if (ex)
6386                 emit_throw_exception (cfg, ex);
6387 }
6388
6389 /*
6390  * Check that the IL instructions at ip are the array initialization
6391  * sequence and return the pointer to the data and the size.
6392  */
6393 static const char*
6394 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6395 {
6396         /*
6397          * newarr[System.Int32]
6398          * dup
6399          * ldtoken field valuetype ...
6400          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6401          */
6402         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6403                 guint32 token = read32 (ip + 7);
6404                 guint32 field_token = read32 (ip + 2);
6405                 guint32 field_index = field_token & 0xffffff;
6406                 guint32 rva;
6407                 const char *data_ptr;
6408                 int size = 0;
6409                 MonoMethod *cmethod;
6410                 MonoClass *dummy_class;
6411                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6412                 int dummy_align;
6413
6414                 if (!field)
6415                         return NULL;
6416
6417                 *out_field_token = field_token;
6418
6419                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6420                 if (!cmethod)
6421                         return NULL;
6422                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6423                         return NULL;
6424                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6425                 case MONO_TYPE_BOOLEAN:
6426                 case MONO_TYPE_I1:
6427                 case MONO_TYPE_U1:
6428                         size = 1; break;
6429                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6430 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6431                 case MONO_TYPE_CHAR:
6432                 case MONO_TYPE_I2:
6433                 case MONO_TYPE_U2:
6434                         size = 2; break;
6435                 case MONO_TYPE_I4:
6436                 case MONO_TYPE_U4:
6437                 case MONO_TYPE_R4:
6438                         size = 4; break;
6439                 case MONO_TYPE_R8:
6440                 case MONO_TYPE_I8:
6441                 case MONO_TYPE_U8:
6442                         size = 8; break;
6443 #endif
6444                 default:
6445                         return NULL;
6446                 }
6447                 size *= len;
6448                 if (size > mono_type_size (field->type, &dummy_align))
6449                     return NULL;
6450                 *out_size = size;
6451                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6452                 if (!method->klass->image->dynamic) {
6453                         field_index = read32 (ip + 2) & 0xffffff;
6454                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6455                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6456                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6457                         /* for aot code we do the lookup on load */
6458                         if (aot && data_ptr)
6459                                 return GUINT_TO_POINTER (rva);
6460                 } else {
6461                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6462                         g_assert (!aot);
6463                         data_ptr = mono_field_get_data (field);
6464                 }
6465                 return data_ptr;
6466         }
6467         return NULL;
6468 }
6469
6470 static void
6471 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6472 {
6473         char *method_fname = mono_method_full_name (method, TRUE);
6474         char *method_code;
6475         MonoMethodHeader *header = mono_method_get_header (method);
6476
6477         if (header->code_size == 0)
6478                 method_code = g_strdup ("method body is empty.");
6479         else
6480                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6481         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6482         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6483         g_free (method_fname);
6484         g_free (method_code);
6485         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6486 }
6487
6488 static void
6489 set_exception_object (MonoCompile *cfg, MonoException *exception)
6490 {
6491         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6492         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6493         cfg->exception_ptr = exception;
6494 }
6495
6496 static void
6497 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6498 {
6499         MonoInst *ins;
6500         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6501         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6502                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6503                 /* Optimize reg-reg moves away */
6504                 /* 
6505                  * Can't optimize other opcodes, since sp[0] might point to
6506                  * the last ins of a decomposed opcode.
6507                  */
6508                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6509         } else {
6510                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6511         }
6512 }
6513
6514 /*
6515  * ldloca inhibits many optimizations so try to get rid of it in common
6516  * cases.
6517  */
6518 static inline unsigned char *
6519 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6520 {
6521         int local, token;
6522         MonoClass *klass;
6523         MonoType *type;
6524
6525         if (size == 1) {
6526                 local = ip [1];
6527                 ip += 2;
6528         } else {
6529                 local = read16 (ip + 2);
6530                 ip += 4;
6531         }
6532         
6533         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6534                 /* From the INITOBJ case */
6535                 token = read32 (ip + 2);
6536                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6537                 CHECK_TYPELOAD (klass);
6538                 type = mini_replace_type (&klass->byval_arg);
6539                 emit_init_local (cfg, local, type, TRUE);
6540                 return ip + 6;
6541         }
6542 load_error:
6543         return NULL;
6544 }
6545
6546 static gboolean
6547 is_exception_class (MonoClass *class)
6548 {
6549         while (class) {
6550                 if (class == mono_defaults.exception_class)
6551                         return TRUE;
6552                 class = class->parent;
6553         }
6554         return FALSE;
6555 }
6556
6557 /*
6558  * is_jit_optimizer_disabled:
6559  *
6560  *   Determine whenever M's assembly has a DebuggableAttribute with the
6561  * IsJITOptimizerDisabled flag set.
6562  */
6563 static gboolean
6564 is_jit_optimizer_disabled (MonoMethod *m)
6565 {
6566         MonoAssembly *ass = m->klass->image->assembly;
6567         MonoCustomAttrInfo* attrs;
6568         static MonoClass *klass;
6569         int i;
6570         gboolean val = FALSE;
6571
6572         g_assert (ass);
6573         if (ass->jit_optimizer_disabled_inited)
6574                 return ass->jit_optimizer_disabled;
6575
6576         if (!klass)
6577                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6578         if (!klass) {
6579                 /* Linked away */
6580                 ass->jit_optimizer_disabled = FALSE;
6581                 mono_memory_barrier ();
6582                 ass->jit_optimizer_disabled_inited = TRUE;
6583                 return FALSE;
6584         }
6585
6586         attrs = mono_custom_attrs_from_assembly (ass);
6587         if (attrs) {
6588                 for (i = 0; i < attrs->num_attrs; ++i) {
6589                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6590                         const gchar *p;
6591                         int len;
6592                         MonoMethodSignature *sig;
6593
6594                         if (!attr->ctor || attr->ctor->klass != klass)
6595                                 continue;
6596                         /* Decode the attribute. See reflection.c */
6597                         len = attr->data_size;
6598                         p = (const char*)attr->data;
6599                         g_assert (read16 (p) == 0x0001);
6600                         p += 2;
6601
6602                         // FIXME: Support named parameters
6603                         sig = mono_method_signature (attr->ctor);
6604                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6605                                 continue;
6606                         /* Two boolean arguments */
6607                         p ++;
6608                         val = *p;
6609                 }
6610                 mono_custom_attrs_free (attrs);
6611         }
6612
6613         ass->jit_optimizer_disabled = val;
6614         mono_memory_barrier ();
6615         ass->jit_optimizer_disabled_inited = TRUE;
6616
6617         return val;
6618 }
6619
6620 static gboolean
6621 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6622 {
6623         gboolean supported_tail_call;
6624         int i;
6625
6626 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6627         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6628 #else
6629         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6630 #endif
6631
6632         for (i = 0; i < fsig->param_count; ++i) {
6633                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6634                         /* These can point to the current method's stack */
6635                         supported_tail_call = FALSE;
6636         }
6637         if (fsig->hasthis && cmethod->klass->valuetype)
6638                 /* this might point to the current method's stack */
6639                 supported_tail_call = FALSE;
6640         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6641                 supported_tail_call = FALSE;
6642         if (cfg->method->save_lmf)
6643                 supported_tail_call = FALSE;
6644         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6645                 supported_tail_call = FALSE;
6646         if (call_opcode != CEE_CALL)
6647                 supported_tail_call = FALSE;
6648
6649         /* Debugging support */
6650 #if 0
6651         if (supported_tail_call) {
6652                 if (!mono_debug_count ())
6653                         supported_tail_call = FALSE;
6654         }
6655 #endif
6656
6657         return supported_tail_call;
6658 }
6659
6660 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6661  * it to the thread local value based on the tls_offset field. Every other kind of access to
6662  * the field causes an assert.
6663  */
6664 static gboolean
6665 is_magic_tls_access (MonoClassField *field)
6666 {
6667         if (strcmp (field->name, "tlsdata"))
6668                 return FALSE;
6669         if (strcmp (field->parent->name, "ThreadLocal`1"))
6670                 return FALSE;
6671         return field->parent->image == mono_defaults.corlib;
6672 }
6673
6674 /* emits the code needed to access a managed tls var (like ThreadStatic)
6675  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6676  * pointer for the current thread.
6677  * Returns the MonoInst* representing the address of the tls var.
6678  */
6679 static MonoInst*
6680 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6681 {
6682         MonoInst *addr;
6683         int static_data_reg, array_reg, dreg;
6684         int offset2_reg, idx_reg;
6685         // inlined access to the tls data
6686         // idx = (offset >> 24) - 1;
6687         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6688         static_data_reg = alloc_ireg (cfg);
6689         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6690         idx_reg = alloc_ireg (cfg);
6691         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6692         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6693         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6694         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6695         array_reg = alloc_ireg (cfg);
6696         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6697         offset2_reg = alloc_ireg (cfg);
6698         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6699         dreg = alloc_ireg (cfg);
6700         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6701         return addr;
6702 }
6703
6704 /*
6705  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6706  * this address is cached per-method in cached_tls_addr.
6707  */
6708 static MonoInst*
6709 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6710 {
6711         MonoInst *load, *addr, *temp, *store, *thread_ins;
6712         MonoClassField *offset_field;
6713
6714         if (*cached_tls_addr) {
6715                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6716                 return addr;
6717         }
6718         thread_ins = mono_get_thread_intrinsic (cfg);
6719         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6720
6721         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6722         if (thread_ins) {
6723                 MONO_ADD_INS (cfg->cbb, thread_ins);
6724         } else {
6725                 MonoMethod *thread_method;
6726                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6727                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6728         }
6729         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6730         addr->klass = mono_class_from_mono_type (tls_field->type);
6731         addr->type = STACK_MP;
6732         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6733         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6734
6735         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6736         return addr;
6737 }
6738
6739 /*
6740  * mono_method_to_ir:
6741  *
6742  *   Translate the .net IL into linear IR.
6743  */
6744 int
6745 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6746                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6747                    guint inline_offset, gboolean is_virtual_call)
6748 {
6749         MonoError error;
6750         MonoInst *ins, **sp, **stack_start;
6751         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6752         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6753         MonoMethod *cmethod, *method_definition;
6754         MonoInst **arg_array;
6755         MonoMethodHeader *header;
6756         MonoImage *image;
6757         guint32 token, ins_flag;
6758         MonoClass *klass;
6759         MonoClass *constrained_call = NULL;
6760         unsigned char *ip, *end, *target, *err_pos;
6761         MonoMethodSignature *sig;
6762         MonoGenericContext *generic_context = NULL;
6763         MonoGenericContainer *generic_container = NULL;
6764         MonoType **param_types;
6765         int i, n, start_new_bblock, dreg;
6766         int num_calls = 0, inline_costs = 0;
6767         int breakpoint_id = 0;
6768         guint num_args;
6769         MonoBoolean security, pinvoke;
6770         MonoSecurityManager* secman = NULL;
6771         MonoDeclSecurityActions actions;
6772         GSList *class_inits = NULL;
6773         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6774         int context_used;
6775         gboolean init_locals, seq_points, skip_dead_blocks;
6776         gboolean disable_inline, sym_seq_points = FALSE;
6777         MonoInst *cached_tls_addr = NULL;
6778         MonoDebugMethodInfo *minfo;
6779         MonoBitSet *seq_point_locs = NULL;
6780         MonoBitSet *seq_point_set_locs = NULL;
6781
6782         disable_inline = is_jit_optimizer_disabled (method);
6783
6784         /* serialization and xdomain stuff may need access to private fields and methods */
6785         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6786         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6787         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6788         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6789         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6790         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6791
6792         dont_verify |= mono_security_smcs_hack_enabled ();
6793
6794         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6795         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6796         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6797         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6798         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6799
6800         image = method->klass->image;
6801         header = mono_method_get_header (method);
6802         if (!header) {
6803                 MonoLoaderError *error;
6804
6805                 if ((error = mono_loader_get_last_error ())) {
6806                         mono_cfg_set_exception (cfg, error->exception_type);
6807                 } else {
6808                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6809                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6810                 }
6811                 goto exception_exit;
6812         }
6813         generic_container = mono_method_get_generic_container (method);
6814         sig = mono_method_signature (method);
6815         num_args = sig->hasthis + sig->param_count;
6816         ip = (unsigned char*)header->code;
6817         cfg->cil_start = ip;
6818         end = ip + header->code_size;
6819         cfg->stat_cil_code_size += header->code_size;
6820
6821         seq_points = cfg->gen_seq_points && cfg->method == method;
6822 #ifdef PLATFORM_ANDROID
6823         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6824 #endif
6825
6826         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6827                 /* We could hit a seq point before attaching to the JIT (#8338) */
6828                 seq_points = FALSE;
6829         }
6830
6831         if (cfg->gen_seq_points && cfg->method == method) {
6832                 minfo = mono_debug_lookup_method (method);
6833                 if (minfo) {
6834                         int i, n_il_offsets;
6835                         int *il_offsets;
6836                         int *line_numbers;
6837
6838                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6839                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6840                         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);
6841                         sym_seq_points = TRUE;
6842                         for (i = 0; i < n_il_offsets; ++i) {
6843                                 if (il_offsets [i] < header->code_size)
6844                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6845                         }
6846                         g_free (il_offsets);
6847                         g_free (line_numbers);
6848                 }
6849         }
6850
6851         /* 
6852          * Methods without init_locals set could cause asserts in various passes
6853          * (#497220). To work around this, we emit dummy initialization opcodes
6854          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
6855          * on some platforms.
6856          */
6857         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
6858                 init_locals = header->init_locals;
6859         else
6860                 init_locals = TRUE;
6861
6862         method_definition = method;
6863         while (method_definition->is_inflated) {
6864                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6865                 method_definition = imethod->declaring;
6866         }
6867
6868         /* SkipVerification is not allowed if core-clr is enabled */
6869         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6870                 dont_verify = TRUE;
6871                 dont_verify_stloc = TRUE;
6872         }
6873
6874         if (sig->is_inflated)
6875                 generic_context = mono_method_get_context (method);
6876         else if (generic_container)
6877                 generic_context = &generic_container->context;
6878         cfg->generic_context = generic_context;
6879
6880         if (!cfg->generic_sharing_context)
6881                 g_assert (!sig->has_type_parameters);
6882
6883         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6884                 g_assert (method->is_inflated);
6885                 g_assert (mono_method_get_context (method)->method_inst);
6886         }
6887         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6888                 g_assert (sig->generic_param_count);
6889
6890         if (cfg->method == method) {
6891                 cfg->real_offset = 0;
6892         } else {
6893                 cfg->real_offset = inline_offset;
6894         }
6895
6896         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6897         cfg->cil_offset_to_bb_len = header->code_size;
6898
6899         cfg->current_method = method;
6900
6901         if (cfg->verbose_level > 2)
6902                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6903
6904         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6905         if (sig->hasthis)
6906                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6907         for (n = 0; n < sig->param_count; ++n)
6908                 param_types [n + sig->hasthis] = sig->params [n];
6909         cfg->arg_types = param_types;
6910
6911         dont_inline = g_list_prepend (dont_inline, method);
6912         if (cfg->method == method) {
6913
6914                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6915                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6916
6917                 /* ENTRY BLOCK */
6918                 NEW_BBLOCK (cfg, start_bblock);
6919                 cfg->bb_entry = start_bblock;
6920                 start_bblock->cil_code = NULL;
6921                 start_bblock->cil_length = 0;
6922 #if defined(__native_client_codegen__)
6923                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6924                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6925                 MONO_ADD_INS (start_bblock, ins);
6926 #endif
6927
6928                 /* EXIT BLOCK */
6929                 NEW_BBLOCK (cfg, end_bblock);
6930                 cfg->bb_exit = end_bblock;
6931                 end_bblock->cil_code = NULL;
6932                 end_bblock->cil_length = 0;
6933                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6934                 g_assert (cfg->num_bblocks == 2);
6935
6936                 arg_array = cfg->args;
6937
6938                 if (header->num_clauses) {
6939                         cfg->spvars = g_hash_table_new (NULL, NULL);
6940                         cfg->exvars = g_hash_table_new (NULL, NULL);
6941                 }
6942                 /* handle exception clauses */
6943                 for (i = 0; i < header->num_clauses; ++i) {
6944                         MonoBasicBlock *try_bb;
6945                         MonoExceptionClause *clause = &header->clauses [i];
6946                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6947                         try_bb->real_offset = clause->try_offset;
6948                         try_bb->try_start = TRUE;
6949                         try_bb->region = ((i + 1) << 8) | clause->flags;
6950                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6951                         tblock->real_offset = clause->handler_offset;
6952                         tblock->flags |= BB_EXCEPTION_HANDLER;
6953
6954                         /*
6955                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6956                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
6957                          */
6958                         if (COMPILE_LLVM (cfg))
6959                                 link_bblock (cfg, try_bb, tblock);
6960
6961                         if (*(ip + clause->handler_offset) == CEE_POP)
6962                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6963
6964                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6965                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6966                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6967                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6968                                 MONO_ADD_INS (tblock, ins);
6969
6970                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6971                                         /* finally clauses already have a seq point */
6972                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6973                                         MONO_ADD_INS (tblock, ins);
6974                                 }
6975
6976                                 /* todo: is a fault block unsafe to optimize? */
6977                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6978                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
6979                         }
6980
6981
6982                         /*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);
6983                           while (p < end) {
6984                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
6985                           }*/
6986                         /* catch and filter blocks get the exception object on the stack */
6987                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
6988                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6989                                 MonoInst *dummy_use;
6990
6991                                 /* mostly like handle_stack_args (), but just sets the input args */
6992                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
6993                                 tblock->in_scount = 1;
6994                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6995                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6996
6997                                 /* 
6998                                  * Add a dummy use for the exvar so its liveness info will be
6999                                  * correct.
7000                                  */
7001                                 cfg->cbb = tblock;
7002                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7003                                 
7004                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7005                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7006                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7007                                         tblock->real_offset = clause->data.filter_offset;
7008                                         tblock->in_scount = 1;
7009                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7010                                         /* The filter block shares the exvar with the handler block */
7011                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7012                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7013                                         MONO_ADD_INS (tblock, ins);
7014                                 }
7015                         }
7016
7017                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7018                                         clause->data.catch_class &&
7019                                         cfg->generic_sharing_context &&
7020                                         mono_class_check_context_used (clause->data.catch_class)) {
7021                                 /*
7022                                  * In shared generic code with catch
7023                                  * clauses containing type variables
7024                                  * the exception handling code has to
7025                                  * be able to get to the rgctx.
7026                                  * Therefore we have to make sure that
7027                                  * the vtable/mrgctx argument (for
7028                                  * static or generic methods) or the
7029                                  * "this" argument (for non-static
7030                                  * methods) are live.
7031                                  */
7032                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7033                                                 mini_method_get_context (method)->method_inst ||
7034                                                 method->klass->valuetype) {
7035                                         mono_get_vtable_var (cfg);
7036                                 } else {
7037                                         MonoInst *dummy_use;
7038
7039                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7040                                 }
7041                         }
7042                 }
7043         } else {
7044                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7045                 cfg->cbb = start_bblock;
7046                 cfg->args = arg_array;
7047                 mono_save_args (cfg, sig, inline_args);
7048         }
7049
7050         /* FIRST CODE BLOCK */
7051         NEW_BBLOCK (cfg, bblock);
7052         bblock->cil_code = ip;
7053         cfg->cbb = bblock;
7054         cfg->ip = ip;
7055
7056         ADD_BBLOCK (cfg, bblock);
7057
7058         if (cfg->method == method) {
7059                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7060                 if (breakpoint_id) {
7061                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7062                         MONO_ADD_INS (bblock, ins);
7063                 }
7064         }
7065
7066         if (mono_security_cas_enabled ())
7067                 secman = mono_security_manager_get_methods ();
7068
7069         security = (secman && mono_security_method_has_declsec (method));
7070         /* at this point having security doesn't mean we have any code to generate */
7071         if (security && (cfg->method == method)) {
7072                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7073                  * And we do not want to enter the next section (with allocation) if we
7074                  * have nothing to generate */
7075                 security = mono_declsec_get_demands (method, &actions);
7076         }
7077
7078         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7079         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7080         if (pinvoke) {
7081                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7082                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7083                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7084
7085                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7086                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7087                                 pinvoke = FALSE;
7088                         }
7089                         if (custom)
7090                                 mono_custom_attrs_free (custom);
7091
7092                         if (pinvoke) {
7093                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7094                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7095                                         pinvoke = FALSE;
7096                                 }
7097                                 if (custom)
7098                                         mono_custom_attrs_free (custom);
7099                         }
7100                 } else {
7101                         /* not a P/Invoke after all */
7102                         pinvoke = FALSE;
7103                 }
7104         }
7105         
7106         /* we use a separate basic block for the initialization code */
7107         NEW_BBLOCK (cfg, init_localsbb);
7108         cfg->bb_init = init_localsbb;
7109         init_localsbb->real_offset = cfg->real_offset;
7110         start_bblock->next_bb = init_localsbb;
7111         init_localsbb->next_bb = bblock;
7112         link_bblock (cfg, start_bblock, init_localsbb);
7113         link_bblock (cfg, init_localsbb, bblock);
7114                 
7115         cfg->cbb = init_localsbb;
7116
7117         if (cfg->gsharedvt && cfg->method == method) {
7118                 MonoGSharedVtMethodInfo *info;
7119                 MonoInst *var, *locals_var;
7120                 int dreg;
7121
7122                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7123                 info->method = cfg->method;
7124                 info->count_entries = 16;
7125                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7126                 cfg->gsharedvt_info = info;
7127
7128                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7129                 /* prevent it from being register allocated */
7130                 //var->flags |= MONO_INST_VOLATILE;
7131                 cfg->gsharedvt_info_var = var;
7132
7133                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7134                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7135
7136                 /* Allocate locals */
7137                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7138                 /* prevent it from being register allocated */
7139                 //locals_var->flags |= MONO_INST_VOLATILE;
7140                 cfg->gsharedvt_locals_var = locals_var;
7141
7142                 dreg = alloc_ireg (cfg);
7143                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7144
7145                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7146                 ins->dreg = locals_var->dreg;
7147                 ins->sreg1 = dreg;
7148                 MONO_ADD_INS (cfg->cbb, ins);
7149                 cfg->gsharedvt_locals_var_ins = ins;
7150                 
7151                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7152                 /*
7153                 if (init_locals)
7154                         ins->flags |= MONO_INST_INIT;
7155                 */
7156         }
7157
7158         /* at this point we know, if security is TRUE, that some code needs to be generated */
7159         if (security && (cfg->method == method)) {
7160                 MonoInst *args [2];
7161
7162                 cfg->stat_cas_demand_generation++;
7163
7164                 if (actions.demand.blob) {
7165                         /* Add code for SecurityAction.Demand */
7166                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7167                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7168                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7169                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7170                 }
7171                 if (actions.noncasdemand.blob) {
7172                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7173                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7174                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7175                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7176                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7177                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7178                 }
7179                 if (actions.demandchoice.blob) {
7180                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7181                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7182                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7183                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7184                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7185                 }
7186         }
7187
7188         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7189         if (pinvoke) {
7190                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7191         }
7192
7193         if (mono_security_core_clr_enabled ()) {
7194                 /* check if this is native code, e.g. an icall or a p/invoke */
7195                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7196                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7197                         if (wrapped) {
7198                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7199                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7200
7201                                 /* if this ia a native call then it can only be JITted from platform code */
7202                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7203                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7204                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7205                                                         mono_get_exception_method_access ();
7206                                                 emit_throw_exception (cfg, ex);
7207                                         }
7208                                 }
7209                         }
7210                 }
7211         }
7212
7213         CHECK_CFG_EXCEPTION;
7214
7215         if (header->code_size == 0)
7216                 UNVERIFIED;
7217
7218         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7219                 ip = err_pos;
7220                 UNVERIFIED;
7221         }
7222
7223         if (cfg->method == method)
7224                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7225
7226         for (n = 0; n < header->num_locals; ++n) {
7227                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7228                         UNVERIFIED;
7229         }
7230         class_inits = NULL;
7231
7232         /* We force the vtable variable here for all shared methods
7233            for the possibility that they might show up in a stack
7234            trace where their exact instantiation is needed. */
7235         if (cfg->generic_sharing_context && method == cfg->method) {
7236                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7237                                 mini_method_get_context (method)->method_inst ||
7238                                 method->klass->valuetype) {
7239                         mono_get_vtable_var (cfg);
7240                 } else {
7241                         /* FIXME: Is there a better way to do this?
7242                            We need the variable live for the duration
7243                            of the whole method. */
7244                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7245                 }
7246         }
7247
7248         /* add a check for this != NULL to inlined methods */
7249         if (is_virtual_call) {
7250                 MonoInst *arg_ins;
7251
7252                 NEW_ARGLOAD (cfg, arg_ins, 0);
7253                 MONO_ADD_INS (cfg->cbb, arg_ins);
7254                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7255         }
7256
7257         skip_dead_blocks = !dont_verify;
7258         if (skip_dead_blocks) {
7259                 original_bb = bb = mono_basic_block_split (method, &error);
7260                 if (!mono_error_ok (&error)) {
7261                         mono_error_cleanup (&error);
7262                         UNVERIFIED;
7263                 }
7264                 g_assert (bb);
7265         }
7266
7267         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7268         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7269
7270         ins_flag = 0;
7271         start_new_bblock = 0;
7272         cfg->cbb = bblock;
7273         while (ip < end) {
7274                 if (cfg->method == method)
7275                         cfg->real_offset = ip - header->code;
7276                 else
7277                         cfg->real_offset = inline_offset;
7278                 cfg->ip = ip;
7279
7280                 context_used = 0;
7281                 
7282                 if (start_new_bblock) {
7283                         bblock->cil_length = ip - bblock->cil_code;
7284                         if (start_new_bblock == 2) {
7285                                 g_assert (ip == tblock->cil_code);
7286                         } else {
7287                                 GET_BBLOCK (cfg, tblock, ip);
7288                         }
7289                         bblock->next_bb = tblock;
7290                         bblock = tblock;
7291                         cfg->cbb = bblock;
7292                         start_new_bblock = 0;
7293                         for (i = 0; i < bblock->in_scount; ++i) {
7294                                 if (cfg->verbose_level > 3)
7295                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7296                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7297                                 *sp++ = ins;
7298                         }
7299                         if (class_inits)
7300                                 g_slist_free (class_inits);
7301                         class_inits = NULL;
7302                 } else {
7303                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7304                                 link_bblock (cfg, bblock, tblock);
7305                                 if (sp != stack_start) {
7306                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7307                                         sp = stack_start;
7308                                         CHECK_UNVERIFIABLE (cfg);
7309                                 }
7310                                 bblock->next_bb = tblock;
7311                                 bblock = tblock;
7312                                 cfg->cbb = bblock;
7313                                 for (i = 0; i < bblock->in_scount; ++i) {
7314                                         if (cfg->verbose_level > 3)
7315                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7316                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7317                                         *sp++ = ins;
7318                                 }
7319                                 g_slist_free (class_inits);
7320                                 class_inits = NULL;
7321                         }
7322                 }
7323
7324                 if (skip_dead_blocks) {
7325                         int ip_offset = ip - header->code;
7326
7327                         if (ip_offset == bb->end)
7328                                 bb = bb->next;
7329
7330                         if (bb->dead) {
7331                                 int op_size = mono_opcode_size (ip, end);
7332                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7333
7334                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7335
7336                                 if (ip_offset + op_size == bb->end) {
7337                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7338                                         MONO_ADD_INS (bblock, ins);
7339                                         start_new_bblock = 1;
7340                                 }
7341
7342                                 ip += op_size;
7343                                 continue;
7344                         }
7345                 }
7346                 /*
7347                  * Sequence points are points where the debugger can place a breakpoint.
7348                  * Currently, we generate these automatically at points where the IL
7349                  * stack is empty.
7350                  */
7351                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7352                         /*
7353                          * Make methods interruptable at the beginning, and at the targets of
7354                          * backward branches.
7355                          * Also, do this at the start of every bblock in methods with clauses too,
7356                          * to be able to handle instructions with inprecise control flow like
7357                          * throw/endfinally.
7358                          * Backward branches are handled at the end of method-to-ir ().
7359                          */
7360                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7361
7362                         /* Avoid sequence points on empty IL like .volatile */
7363                         // FIXME: Enable this
7364                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7365                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7366                         if (sp != stack_start)
7367                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7368                         MONO_ADD_INS (cfg->cbb, ins);
7369
7370                         if (sym_seq_points)
7371                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7372                 }
7373
7374                 bblock->real_offset = cfg->real_offset;
7375
7376                 if ((cfg->method == method) && cfg->coverage_info) {
7377                         guint32 cil_offset = ip - header->code;
7378                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7379
7380                         /* TODO: Use an increment here */
7381 #if defined(TARGET_X86)
7382                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7383                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7384                         ins->inst_imm = 1;
7385                         MONO_ADD_INS (cfg->cbb, ins);
7386 #else
7387                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7388                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7389 #endif
7390                 }
7391
7392                 if (cfg->verbose_level > 3)
7393                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7394
7395                 switch (*ip) {
7396                 case CEE_NOP:
7397                         if (seq_points && !sym_seq_points && sp != stack_start) {
7398                                 /*
7399                                  * The C# compiler uses these nops to notify the JIT that it should
7400                                  * insert seq points.
7401                                  */
7402                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7403                                 MONO_ADD_INS (cfg->cbb, ins);
7404                         }
7405                         if (cfg->keep_cil_nops)
7406                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7407                         else
7408                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7409                         ip++;
7410                         MONO_ADD_INS (bblock, ins);
7411                         break;
7412                 case CEE_BREAK:
7413                         if (should_insert_brekpoint (cfg->method)) {
7414                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7415                         } else {
7416                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7417                         }
7418                         ip++;
7419                         MONO_ADD_INS (bblock, ins);
7420                         break;
7421                 case CEE_LDARG_0:
7422                 case CEE_LDARG_1:
7423                 case CEE_LDARG_2:
7424                 case CEE_LDARG_3:
7425                         CHECK_STACK_OVF (1);
7426                         n = (*ip)-CEE_LDARG_0;
7427                         CHECK_ARG (n);
7428                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7429                         ip++;
7430                         *sp++ = ins;
7431                         break;
7432                 case CEE_LDLOC_0:
7433                 case CEE_LDLOC_1:
7434                 case CEE_LDLOC_2:
7435                 case CEE_LDLOC_3:
7436                         CHECK_STACK_OVF (1);
7437                         n = (*ip)-CEE_LDLOC_0;
7438                         CHECK_LOCAL (n);
7439                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7440                         ip++;
7441                         *sp++ = ins;
7442                         break;
7443                 case CEE_STLOC_0:
7444                 case CEE_STLOC_1:
7445                 case CEE_STLOC_2:
7446                 case CEE_STLOC_3: {
7447                         CHECK_STACK (1);
7448                         n = (*ip)-CEE_STLOC_0;
7449                         CHECK_LOCAL (n);
7450                         --sp;
7451                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7452                                 UNVERIFIED;
7453                         emit_stloc_ir (cfg, sp, header, n);
7454                         ++ip;
7455                         inline_costs += 1;
7456                         break;
7457                         }
7458                 case CEE_LDARG_S:
7459                         CHECK_OPSIZE (2);
7460                         CHECK_STACK_OVF (1);
7461                         n = ip [1];
7462                         CHECK_ARG (n);
7463                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7464                         *sp++ = ins;
7465                         ip += 2;
7466                         break;
7467                 case CEE_LDARGA_S:
7468                         CHECK_OPSIZE (2);
7469                         CHECK_STACK_OVF (1);
7470                         n = ip [1];
7471                         CHECK_ARG (n);
7472                         NEW_ARGLOADA (cfg, ins, n);
7473                         MONO_ADD_INS (cfg->cbb, ins);
7474                         *sp++ = ins;
7475                         ip += 2;
7476                         break;
7477                 case CEE_STARG_S:
7478                         CHECK_OPSIZE (2);
7479                         CHECK_STACK (1);
7480                         --sp;
7481                         n = ip [1];
7482                         CHECK_ARG (n);
7483                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7484                                 UNVERIFIED;
7485                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7486                         ip += 2;
7487                         break;
7488                 case CEE_LDLOC_S:
7489                         CHECK_OPSIZE (2);
7490                         CHECK_STACK_OVF (1);
7491                         n = ip [1];
7492                         CHECK_LOCAL (n);
7493                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7494                         *sp++ = ins;
7495                         ip += 2;
7496                         break;
7497                 case CEE_LDLOCA_S: {
7498                         unsigned char *tmp_ip;
7499                         CHECK_OPSIZE (2);
7500                         CHECK_STACK_OVF (1);
7501                         CHECK_LOCAL (ip [1]);
7502
7503                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7504                                 ip = tmp_ip;
7505                                 inline_costs += 1;
7506                                 break;
7507                         }
7508
7509                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7510                         *sp++ = ins;
7511                         ip += 2;
7512                         break;
7513                 }
7514                 case CEE_STLOC_S:
7515                         CHECK_OPSIZE (2);
7516                         CHECK_STACK (1);
7517                         --sp;
7518                         CHECK_LOCAL (ip [1]);
7519                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7520                                 UNVERIFIED;
7521                         emit_stloc_ir (cfg, sp, header, ip [1]);
7522                         ip += 2;
7523                         inline_costs += 1;
7524                         break;
7525                 case CEE_LDNULL:
7526                         CHECK_STACK_OVF (1);
7527                         EMIT_NEW_PCONST (cfg, ins, NULL);
7528                         ins->type = STACK_OBJ;
7529                         ++ip;
7530                         *sp++ = ins;
7531                         break;
7532                 case CEE_LDC_I4_M1:
7533                         CHECK_STACK_OVF (1);
7534                         EMIT_NEW_ICONST (cfg, ins, -1);
7535                         ++ip;
7536                         *sp++ = ins;
7537                         break;
7538                 case CEE_LDC_I4_0:
7539                 case CEE_LDC_I4_1:
7540                 case CEE_LDC_I4_2:
7541                 case CEE_LDC_I4_3:
7542                 case CEE_LDC_I4_4:
7543                 case CEE_LDC_I4_5:
7544                 case CEE_LDC_I4_6:
7545                 case CEE_LDC_I4_7:
7546                 case CEE_LDC_I4_8:
7547                         CHECK_STACK_OVF (1);
7548                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7549                         ++ip;
7550                         *sp++ = ins;
7551                         break;
7552                 case CEE_LDC_I4_S:
7553                         CHECK_OPSIZE (2);
7554                         CHECK_STACK_OVF (1);
7555                         ++ip;
7556                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7557                         ++ip;
7558                         *sp++ = ins;
7559                         break;
7560                 case CEE_LDC_I4:
7561                         CHECK_OPSIZE (5);
7562                         CHECK_STACK_OVF (1);
7563                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7564                         ip += 5;
7565                         *sp++ = ins;
7566                         break;
7567                 case CEE_LDC_I8:
7568                         CHECK_OPSIZE (9);
7569                         CHECK_STACK_OVF (1);
7570                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7571                         ins->type = STACK_I8;
7572                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7573                         ++ip;
7574                         ins->inst_l = (gint64)read64 (ip);
7575                         MONO_ADD_INS (bblock, ins);
7576                         ip += 8;
7577                         *sp++ = ins;
7578                         break;
7579                 case CEE_LDC_R4: {
7580                         float *f;
7581                         gboolean use_aotconst = FALSE;
7582
7583 #ifdef TARGET_POWERPC
7584                         /* FIXME: Clean this up */
7585                         if (cfg->compile_aot)
7586                                 use_aotconst = TRUE;
7587 #endif
7588
7589                         /* FIXME: we should really allocate this only late in the compilation process */
7590                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7591                         CHECK_OPSIZE (5);
7592                         CHECK_STACK_OVF (1);
7593
7594                         if (use_aotconst) {
7595                                 MonoInst *cons;
7596                                 int dreg;
7597
7598                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7599
7600                                 dreg = alloc_freg (cfg);
7601                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7602                                 ins->type = STACK_R8;
7603                         } else {
7604                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7605                                 ins->type = STACK_R8;
7606                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7607                                 ins->inst_p0 = f;
7608                                 MONO_ADD_INS (bblock, ins);
7609                         }
7610                         ++ip;
7611                         readr4 (ip, f);
7612                         ip += 4;
7613                         *sp++ = ins;                    
7614                         break;
7615                 }
7616                 case CEE_LDC_R8: {
7617                         double *d;
7618                         gboolean use_aotconst = FALSE;
7619
7620 #ifdef TARGET_POWERPC
7621                         /* FIXME: Clean this up */
7622                         if (cfg->compile_aot)
7623                                 use_aotconst = TRUE;
7624 #endif
7625
7626                         /* FIXME: we should really allocate this only late in the compilation process */
7627                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7628                         CHECK_OPSIZE (9);
7629                         CHECK_STACK_OVF (1);
7630
7631                         if (use_aotconst) {
7632                                 MonoInst *cons;
7633                                 int dreg;
7634
7635                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7636
7637                                 dreg = alloc_freg (cfg);
7638                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7639                                 ins->type = STACK_R8;
7640                         } else {
7641                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7642                                 ins->type = STACK_R8;
7643                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7644                                 ins->inst_p0 = d;
7645                                 MONO_ADD_INS (bblock, ins);
7646                         }
7647                         ++ip;
7648                         readr8 (ip, d);
7649                         ip += 8;
7650                         *sp++ = ins;
7651                         break;
7652                 }
7653                 case CEE_DUP: {
7654                         MonoInst *temp, *store;
7655                         CHECK_STACK (1);
7656                         CHECK_STACK_OVF (1);
7657                         sp--;
7658                         ins = *sp;
7659
7660                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7661                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7662
7663                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7664                         *sp++ = ins;
7665
7666                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7667                         *sp++ = ins;
7668
7669                         ++ip;
7670                         inline_costs += 2;
7671                         break;
7672                 }
7673                 case CEE_POP:
7674                         CHECK_STACK (1);
7675                         ip++;
7676                         --sp;
7677
7678 #ifdef TARGET_X86
7679                         if (sp [0]->type == STACK_R8)
7680                                 /* we need to pop the value from the x86 FP stack */
7681                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7682 #endif
7683                         break;
7684                 case CEE_JMP: {
7685                         MonoCallInst *call;
7686
7687                         INLINE_FAILURE ("jmp");
7688                         GSHAREDVT_FAILURE (*ip);
7689
7690                         CHECK_OPSIZE (5);
7691                         if (stack_start != sp)
7692                                 UNVERIFIED;
7693                         token = read32 (ip + 1);
7694                         /* FIXME: check the signature matches */
7695                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7696
7697                         if (!cmethod || mono_loader_get_last_error ())
7698                                 LOAD_ERROR;
7699  
7700                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7701                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7702
7703                         if (mono_security_cas_enabled ())
7704                                 CHECK_CFG_EXCEPTION;
7705
7706                         if (ARCH_HAVE_OP_TAIL_CALL) {
7707                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7708                                 int i, n;
7709
7710                                 /* Handle tail calls similarly to calls */
7711                                 n = fsig->param_count + fsig->hasthis;
7712
7713                                 DISABLE_AOT (cfg);
7714
7715                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7716                                 call->method = cmethod;
7717                                 call->tail_call = TRUE;
7718                                 call->signature = mono_method_signature (cmethod);
7719                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7720                                 call->inst.inst_p0 = cmethod;
7721                                 for (i = 0; i < n; ++i)
7722                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7723
7724                                 mono_arch_emit_call (cfg, call);
7725                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7726                         } else {
7727                                 for (i = 0; i < num_args; ++i)
7728                                         /* Prevent arguments from being optimized away */
7729                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7730
7731                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7732                                 ins = (MonoInst*)call;
7733                                 ins->inst_p0 = cmethod;
7734                                 MONO_ADD_INS (bblock, ins);
7735                         }
7736
7737                         ip += 5;
7738                         start_new_bblock = 1;
7739                         break;
7740                 }
7741                 case CEE_CALLI:
7742                 case CEE_CALL:
7743                 case CEE_CALLVIRT: {
7744                         MonoInst *addr = NULL;
7745                         MonoMethodSignature *fsig = NULL;
7746                         int array_rank = 0;
7747                         int virtual = *ip == CEE_CALLVIRT;
7748                         int calli = *ip == CEE_CALLI;
7749                         gboolean pass_imt_from_rgctx = FALSE;
7750                         MonoInst *imt_arg = NULL;
7751                         MonoInst *keep_this_alive = NULL;
7752                         gboolean pass_vtable = FALSE;
7753                         gboolean pass_mrgctx = FALSE;
7754                         MonoInst *vtable_arg = NULL;
7755                         gboolean check_this = FALSE;
7756                         gboolean supported_tail_call = FALSE;
7757                         gboolean tail_call = FALSE;
7758                         gboolean need_seq_point = FALSE;
7759                         guint32 call_opcode = *ip;
7760                         gboolean emit_widen = TRUE;
7761                         gboolean push_res = TRUE;
7762                         gboolean skip_ret = FALSE;
7763                         gboolean delegate_invoke = FALSE;
7764
7765                         CHECK_OPSIZE (5);
7766                         token = read32 (ip + 1);
7767
7768                         ins = NULL;
7769
7770                         if (calli) {
7771                                 //GSHAREDVT_FAILURE (*ip);
7772                                 cmethod = NULL;
7773                                 CHECK_STACK (1);
7774                                 --sp;
7775                                 addr = *sp;
7776                                 fsig = mini_get_signature (method, token, generic_context);
7777                                 n = fsig->param_count + fsig->hasthis;
7778
7779                                 if (method->dynamic && fsig->pinvoke) {
7780                                         MonoInst *args [3];
7781
7782                                         /*
7783                                          * This is a call through a function pointer using a pinvoke
7784                                          * signature. Have to create a wrapper and call that instead.
7785                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7786                                          * instead based on the signature.
7787                                          */
7788                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7789                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7790                                         args [2] = addr;
7791                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7792                                 }
7793                         } else {
7794                                 MonoMethod *cil_method;
7795
7796                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7797                                 cil_method = cmethod;
7798                                 
7799                                 if (constrained_call) {
7800                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7801                                                 if (cfg->verbose_level > 2)
7802                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7803                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7804                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7805                                                           cfg->generic_sharing_context)) {
7806                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7807                                                 }
7808                                         } else {
7809                                                 if (cfg->verbose_level > 2)
7810                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7811
7812                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7813                                                         /* 
7814                                                          * This is needed since get_method_constrained can't find 
7815                                                          * the method in klass representing a type var.
7816                                                          * The type var is guaranteed to be a reference type in this
7817                                                          * case.
7818                                                          */
7819                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7820                                                                 g_assert (!cmethod->klass->valuetype);
7821                                                 } else {
7822                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7823                                                 }
7824                                         }
7825                                 }
7826                                         
7827                                 if (!cmethod || mono_loader_get_last_error ())
7828                                         LOAD_ERROR;
7829                                 if (!dont_verify && !cfg->skip_visibility) {
7830                                         MonoMethod *target_method = cil_method;
7831                                         if (method->is_inflated) {
7832                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7833                                         }
7834                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7835                                                 !mono_method_can_access_method (method, cil_method))
7836                                                 METHOD_ACCESS_FAILURE;
7837                                 }
7838
7839                                 if (mono_security_core_clr_enabled ())
7840                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7841
7842                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7843                                         /* MS.NET seems to silently convert this to a callvirt */
7844                                         virtual = 1;
7845
7846                                 {
7847                                         /*
7848                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7849                                          * converts to a callvirt.
7850                                          *
7851                                          * tests/bug-515884.il is an example of this behavior
7852                                          */
7853                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7854                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7855                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7856                                                 virtual = 1;
7857                                 }
7858
7859                                 if (!cmethod->klass->inited)
7860                                         if (!mono_class_init (cmethod->klass))
7861                                                 TYPE_LOAD_ERROR (cmethod->klass);
7862
7863                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7864                                     mini_class_is_system_array (cmethod->klass)) {
7865                                         array_rank = cmethod->klass->rank;
7866                                         fsig = mono_method_signature (cmethod);
7867                                 } else {
7868                                         fsig = mono_method_signature (cmethod);
7869
7870                                         if (!fsig)
7871                                                 LOAD_ERROR;
7872
7873                                         if (fsig->pinvoke) {
7874                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7875                                                         check_for_pending_exc, cfg->compile_aot);
7876                                                 fsig = mono_method_signature (wrapper);
7877                                         } else if (constrained_call) {
7878                                                 fsig = mono_method_signature (cmethod);
7879                                         } else {
7880                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7881                                         }
7882                                 }
7883
7884                                 mono_save_token_info (cfg, image, token, cil_method);
7885
7886                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7887                                         /*
7888                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7889                                          * foo (bar (), baz ())
7890                                          * works correctly. MS does this also:
7891                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7892                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7893                                          * even for simple cases, like:
7894                                          * int i = foo ();
7895                                          */
7896                                         /* Special case a few common successor opcodes */
7897                                         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)))
7898                                                 need_seq_point = TRUE;
7899                                 }
7900
7901                                 n = fsig->param_count + fsig->hasthis;
7902
7903                                 /* Don't support calls made using type arguments for now */
7904                                 /*
7905                                 if (cfg->gsharedvt) {
7906                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7907                                                 GSHAREDVT_FAILURE (*ip);
7908                                 }
7909                                 */
7910
7911                                 if (mono_security_cas_enabled ()) {
7912                                         if (check_linkdemand (cfg, method, cmethod))
7913                                                 INLINE_FAILURE ("linkdemand");
7914                                         CHECK_CFG_EXCEPTION;
7915                                 }
7916
7917                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7918                                         g_assert_not_reached ();
7919                         }
7920
7921                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7922                                 UNVERIFIED;
7923
7924                         if (!cfg->generic_sharing_context && cmethod)
7925                                 g_assert (!mono_method_check_context_used (cmethod));
7926
7927                         CHECK_STACK (n);
7928
7929                         //g_assert (!virtual || fsig->hasthis);
7930
7931                         sp -= n;
7932
7933                         if (constrained_call) {
7934                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7935                                         /*
7936                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7937                                          */
7938                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7939                                                 /* The 'Own method' case below */
7940                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7941                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7942                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7943                                                            (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)) &&
7944                                                            (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]))))) {
7945                                                 MonoInst *args [16];
7946
7947                                                 /*
7948                                                  * This case handles calls to
7949                                                  * - object:ToString()/Equals()/GetHashCode(),
7950                                                  * - System.IComparable<T>:CompareTo()
7951                                                  * - System.IEquatable<T>:Equals ()
7952                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7953                                                  */
7954
7955                                                 args [0] = sp [0];
7956                                                 if (mono_method_check_context_used (cmethod))
7957                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7958                                                 else
7959                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7960                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7961
7962                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7963                                                 if (fsig->hasthis && fsig->param_count) {
7964                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7965                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7966                                                         ins->dreg = alloc_preg (cfg);
7967                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7968                                                         MONO_ADD_INS (cfg->cbb, ins);
7969                                                         args [4] = ins;
7970
7971                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7972                                                                 int addr_reg;
7973
7974                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
7975
7976                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
7977                                                                 addr_reg = ins->dreg;
7978                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
7979                                                         } else {
7980                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
7981                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
7982                                                         }
7983                                                 } else {
7984                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
7985                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
7986                                                 }
7987                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
7988                                                 emit_widen = FALSE;
7989
7990                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
7991                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
7992                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
7993                                                         MonoInst *add;
7994
7995                                                         /* Unbox */
7996                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
7997                                                         MONO_ADD_INS (cfg->cbb, add);
7998                                                         /* Load value */
7999                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8000                                                         MONO_ADD_INS (cfg->cbb, ins);
8001                                                         /* ins represents the call result */
8002                                                 }
8003
8004                                                 goto call_end;
8005                                         } else {
8006                                                 GSHAREDVT_FAILURE (*ip);
8007                                         }
8008                                 }
8009                                 /*
8010                                  * We have the `constrained.' prefix opcode.
8011                                  */
8012                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8013                                         /*
8014                                          * The type parameter is instantiated as a valuetype,
8015                                          * but that type doesn't override the method we're
8016                                          * calling, so we need to box `this'.
8017                                          */
8018                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8019                                         ins->klass = constrained_call;
8020                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8021                                         CHECK_CFG_EXCEPTION;
8022                                 } else if (!constrained_call->valuetype) {
8023                                         int dreg = alloc_ireg_ref (cfg);
8024
8025                                         /*
8026                                          * The type parameter is instantiated as a reference
8027                                          * type.  We have a managed pointer on the stack, so
8028                                          * we need to dereference it here.
8029                                          */
8030                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8031                                         ins->type = STACK_OBJ;
8032                                         sp [0] = ins;
8033                                 } else {
8034                                         if (cmethod->klass->valuetype) {
8035                                                 /* Own method */
8036                                         } else {
8037                                                 /* Interface method */
8038                                                 int ioffset, slot;
8039
8040                                                 mono_class_setup_vtable (constrained_call);
8041                                                 CHECK_TYPELOAD (constrained_call);
8042                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8043                                                 if (ioffset == -1)
8044                                                         TYPE_LOAD_ERROR (constrained_call);
8045                                                 slot = mono_method_get_vtable_slot (cmethod);
8046                                                 if (slot == -1)
8047                                                         TYPE_LOAD_ERROR (cmethod->klass);
8048                                                 cmethod = constrained_call->vtable [ioffset + slot];
8049
8050                                                 if (cmethod->klass == mono_defaults.enum_class) {
8051                                                         /* Enum implements some interfaces, so treat this as the first case */
8052                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8053                                                         ins->klass = constrained_call;
8054                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8055                                                         CHECK_CFG_EXCEPTION;
8056                                                 }
8057                                         }
8058                                         virtual = 0;
8059                                 }
8060                                 constrained_call = NULL;
8061                         }
8062
8063                         if (!calli && check_call_signature (cfg, fsig, sp))
8064                                 UNVERIFIED;
8065
8066 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8067                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8068                                 delegate_invoke = TRUE;
8069 #endif
8070
8071                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8072                                 bblock = cfg->cbb;
8073                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8074                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8075                                         emit_widen = FALSE;
8076                                 }
8077
8078                                 goto call_end;
8079                         }
8080
8081                         /* 
8082                          * If the callee is a shared method, then its static cctor
8083                          * might not get called after the call was patched.
8084                          */
8085                         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)) {
8086                                 emit_generic_class_init (cfg, cmethod->klass);
8087                                 CHECK_TYPELOAD (cmethod->klass);
8088                         }
8089
8090                         if (cmethod)
8091                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8092
8093                         if (cfg->generic_sharing_context && cmethod) {
8094                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8095
8096                                 context_used = mini_method_check_context_used (cfg, cmethod);
8097
8098                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8099                                         /* Generic method interface
8100                                            calls are resolved via a
8101                                            helper function and don't
8102                                            need an imt. */
8103                                         if (!cmethod_context || !cmethod_context->method_inst)
8104                                                 pass_imt_from_rgctx = TRUE;
8105                                 }
8106
8107                                 /*
8108                                  * If a shared method calls another
8109                                  * shared method then the caller must
8110                                  * have a generic sharing context
8111                                  * because the magic trampoline
8112                                  * requires it.  FIXME: We shouldn't
8113                                  * have to force the vtable/mrgctx
8114                                  * variable here.  Instead there
8115                                  * should be a flag in the cfg to
8116                                  * request a generic sharing context.
8117                                  */
8118                                 if (context_used &&
8119                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8120                                         mono_get_vtable_var (cfg);
8121                         }
8122
8123                         if (pass_vtable) {
8124                                 if (context_used) {
8125                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8126                                 } else {
8127                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8128
8129                                         CHECK_TYPELOAD (cmethod->klass);
8130                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8131                                 }
8132                         }
8133
8134                         if (pass_mrgctx) {
8135                                 g_assert (!vtable_arg);
8136
8137                                 if (!cfg->compile_aot) {
8138                                         /* 
8139                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8140                                          * for type load errors before.
8141                                          */
8142                                         mono_class_setup_vtable (cmethod->klass);
8143                                         CHECK_TYPELOAD (cmethod->klass);
8144                                 }
8145
8146                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8147
8148                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8149                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8150                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8151                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8152                                         if (virtual)
8153                                                 check_this = TRUE;
8154                                         virtual = 0;
8155                                 }
8156                         }
8157
8158                         if (pass_imt_from_rgctx) {
8159                                 g_assert (!pass_vtable);
8160                                 g_assert (cmethod);
8161
8162                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8163                                         cmethod, MONO_RGCTX_INFO_METHOD);
8164                         }
8165
8166                         if (check_this)
8167                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8168
8169                         /* Calling virtual generic methods */
8170                         if (cmethod && virtual && 
8171                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8172                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8173                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8174                             fsig->generic_param_count && 
8175                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8176                                 MonoInst *this_temp, *this_arg_temp, *store;
8177                                 MonoInst *iargs [4];
8178                                 gboolean use_imt = FALSE;
8179
8180                                 g_assert (fsig->is_inflated);
8181
8182                                 /* Prevent inlining of methods that contain indirect calls */
8183                                 INLINE_FAILURE ("virtual generic call");
8184
8185                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8186                                         GSHAREDVT_FAILURE (*ip);
8187
8188 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8189                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8190                                         use_imt = TRUE;
8191 #endif
8192
8193                                 if (use_imt) {
8194                                         g_assert (!imt_arg);
8195                                         if (!context_used)
8196                                                 g_assert (cmethod->is_inflated);
8197                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8198                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8199                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8200                                 } else {
8201                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8202                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8203                                         MONO_ADD_INS (bblock, store);
8204
8205                                         /* FIXME: This should be a managed pointer */
8206                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8207
8208                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8209                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8210                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8211                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8212                                         addr = mono_emit_jit_icall (cfg,
8213                                                                                                 mono_helper_compile_generic_method, iargs);
8214
8215                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8216
8217                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8218                                 }
8219
8220                                 goto call_end;
8221                         }
8222
8223                         /*
8224                          * Implement a workaround for the inherent races involved in locking:
8225                          * Monitor.Enter ()
8226                          * try {
8227                          * } finally {
8228                          *    Monitor.Exit ()
8229                          * }
8230                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8231                          * try block, the Exit () won't be executed, see:
8232                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8233                          * To work around this, we extend such try blocks to include the last x bytes
8234                          * of the Monitor.Enter () call.
8235                          */
8236                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8237                                 MonoBasicBlock *tbb;
8238
8239                                 GET_BBLOCK (cfg, tbb, ip + 5);
8240                                 /* 
8241                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8242                                  * from Monitor.Enter like ArgumentNullException.
8243                                  */
8244                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8245                                         /* Mark this bblock as needing to be extended */
8246                                         tbb->extend_try_block = TRUE;
8247                                 }
8248                         }
8249
8250                         /* Conversion to a JIT intrinsic */
8251                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8252                                 bblock = cfg->cbb;
8253                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8254                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8255                                         emit_widen = FALSE;
8256                                 }
8257                                 goto call_end;
8258                         }
8259
8260                         /* Inlining */
8261                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8262                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8263                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8264                                  !g_list_find (dont_inline, cmethod)) {
8265                                 int costs;
8266                                 gboolean always = FALSE;
8267
8268                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8269                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8270                                         /* Prevent inlining of methods that call wrappers */
8271                                         INLINE_FAILURE ("wrapper call");
8272                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8273                                         always = TRUE;
8274                                 }
8275
8276                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8277                                 if (costs) {
8278                                         cfg->real_offset += 5;
8279                                         bblock = cfg->cbb;
8280
8281                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8282                                                 /* *sp is already set by inline_method */
8283                                                 sp++;
8284                                                 push_res = FALSE;
8285                                         }
8286
8287                                         inline_costs += costs;
8288
8289                                         goto call_end;
8290                                 }
8291                         }
8292
8293                         /* Tail recursion elimination */
8294                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8295                                 gboolean has_vtargs = FALSE;
8296                                 int i;
8297
8298                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8299                                 INLINE_FAILURE ("tail call");
8300
8301                                 /* keep it simple */
8302                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8303                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8304                                                 has_vtargs = TRUE;
8305                                 }
8306
8307                                 if (!has_vtargs) {
8308                                         for (i = 0; i < n; ++i)
8309                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8310                                         MONO_INST_NEW (cfg, ins, OP_BR);
8311                                         MONO_ADD_INS (bblock, ins);
8312                                         tblock = start_bblock->out_bb [0];
8313                                         link_bblock (cfg, bblock, tblock);
8314                                         ins->inst_target_bb = tblock;
8315                                         start_new_bblock = 1;
8316
8317                                         /* skip the CEE_RET, too */
8318                                         if (ip_in_bb (cfg, bblock, ip + 5))
8319                                                 skip_ret = TRUE;
8320                                         push_res = FALSE;
8321                                         goto call_end;
8322                                 }
8323                         }
8324
8325                         inline_costs += 10 * num_calls++;
8326
8327                         /*
8328                          * Making generic calls out of gsharedvt methods.
8329                          */
8330                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8331                                 MonoRgctxInfoType info_type;
8332
8333                                 if (virtual) {
8334                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8335                                                 //GSHAREDVT_FAILURE (*ip);
8336                                         // disable for possible remoting calls
8337                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8338                                                 GSHAREDVT_FAILURE (*ip);
8339                                         if (fsig->generic_param_count) {
8340                                                 /* virtual generic call */
8341                                                 g_assert (mono_use_imt);
8342                                                 g_assert (!imt_arg);
8343                                                 /* Same as the virtual generic case above */
8344                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8345                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8346                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8347                                                 vtable_arg = NULL;
8348                                         }
8349                                 }
8350
8351                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8352                                         /* test_0_multi_dim_arrays () in gshared.cs */
8353                                         GSHAREDVT_FAILURE (*ip);
8354
8355                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8356                                         keep_this_alive = sp [0];
8357
8358                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8359                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8360                                 else
8361                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8362                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8363
8364                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8365                                 goto call_end;
8366                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8367                                 /*
8368                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8369                                  */
8370                                 MonoInst *callee = addr;
8371
8372                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8373                                         /* Not tested */
8374                                         GSHAREDVT_FAILURE (*ip);
8375
8376                                 addr = emit_get_rgctx_sig (cfg, context_used,
8377                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8378                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8379                                 goto call_end;
8380                         }
8381
8382                         /* Generic sharing */
8383                         /* FIXME: only do this for generic methods if
8384                            they are not shared! */
8385                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8386                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8387                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8388                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8389                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8390                                 INLINE_FAILURE ("gshared");
8391
8392                                 g_assert (cfg->generic_sharing_context && cmethod);
8393                                 g_assert (!addr);
8394
8395                                 /*
8396                                  * We are compiling a call to a
8397                                  * generic method from shared code,
8398                                  * which means that we have to look up
8399                                  * the method in the rgctx and do an
8400                                  * indirect call.
8401                                  */
8402                                 if (fsig->hasthis)
8403                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8404
8405                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8406                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8407                                 goto call_end;
8408                         }
8409
8410                         /* Indirect calls */
8411                         if (addr) {
8412                                 if (call_opcode == CEE_CALL)
8413                                         g_assert (context_used);
8414                                 else if (call_opcode == CEE_CALLI)
8415                                         g_assert (!vtable_arg);
8416                                 else
8417                                         /* FIXME: what the hell is this??? */
8418                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8419                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8420
8421                                 /* Prevent inlining of methods with indirect calls */
8422                                 INLINE_FAILURE ("indirect call");
8423
8424                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8425                                         int info_type;
8426                                         gpointer info_data;
8427
8428                                         /* 
8429                                          * Instead of emitting an indirect call, emit a direct call
8430                                          * with the contents of the aotconst as the patch info.
8431                                          */
8432                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8433                                                 info_type = addr->inst_c1;
8434                                                 info_data = addr->inst_p0;
8435                                         } else {
8436                                                 info_type = addr->inst_right->inst_c1;
8437                                                 info_data = addr->inst_right->inst_left;
8438                                         }
8439                                         
8440                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8441                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8442                                                 NULLIFY_INS (addr);
8443                                                 goto call_end;
8444                                         }
8445                                 }
8446                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8447                                 goto call_end;
8448                         }
8449                                         
8450                         /* Array methods */
8451                         if (array_rank) {
8452                                 MonoInst *addr;
8453
8454                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8455                                         MonoInst *val = sp [fsig->param_count];
8456
8457                                         if (val->type == STACK_OBJ) {
8458                                                 MonoInst *iargs [2];
8459
8460                                                 iargs [0] = sp [0];
8461                                                 iargs [1] = val;
8462                                                 
8463                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8464                                         }
8465                                         
8466                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8467                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8468                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8469                                                 emit_write_barrier (cfg, addr, val);
8470                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8471                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8472
8473                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8474                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8475                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8476                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8477                                         CHECK_TYPELOAD (cmethod->klass);
8478                                         
8479                                         readonly = FALSE;
8480                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8481                                         ins = addr;
8482                                 } else {
8483                                         g_assert_not_reached ();
8484                                 }
8485
8486                                 emit_widen = FALSE;
8487                                 goto call_end;
8488                         }
8489
8490                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8491                         if (ins)
8492                                 goto call_end;
8493
8494                         /* Tail prefix / tail call optimization */
8495
8496                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8497                         /* FIXME: runtime generic context pointer for jumps? */
8498                         /* FIXME: handle this for generic sharing eventually */
8499                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8500                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8501                                 supported_tail_call = TRUE;
8502
8503                         if (supported_tail_call) {
8504                                 MonoCallInst *call;
8505
8506                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8507                                 INLINE_FAILURE ("tail call");
8508
8509                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8510
8511                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8512                                         /* Handle tail calls similarly to normal calls */
8513                                         tail_call = TRUE;
8514                                 } else {
8515                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8516                                         call->tail_call = TRUE;
8517                                         call->method = cmethod;
8518                                         call->signature = mono_method_signature (cmethod);
8519
8520                                         /*
8521                                          * We implement tail calls by storing the actual arguments into the 
8522                                          * argument variables, then emitting a CEE_JMP.
8523                                          */
8524                                         for (i = 0; i < n; ++i) {
8525                                                 /* Prevent argument from being register allocated */
8526                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8527                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8528                                         }
8529                                         ins = (MonoInst*)call;
8530                                         ins->inst_p0 = cmethod;
8531                                         ins->inst_p1 = arg_array [0];
8532                                         MONO_ADD_INS (bblock, ins);
8533                                         link_bblock (cfg, bblock, end_bblock);                  
8534                                         start_new_bblock = 1;
8535
8536                                         // FIXME: Eliminate unreachable epilogs
8537
8538                                         /*
8539                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8540                                          * only reachable from this call.
8541                                          */
8542                                         GET_BBLOCK (cfg, tblock, ip + 5);
8543                                         if (tblock == bblock || tblock->in_count == 0)
8544                                                 skip_ret = TRUE;
8545                                         push_res = FALSE;
8546
8547                                         goto call_end;
8548                                 }
8549                         }
8550
8551                         /* 
8552                          * Synchronized wrappers.
8553                          * Its hard to determine where to replace a method with its synchronized
8554                          * wrapper without causing an infinite recursion. The current solution is
8555                          * to add the synchronized wrapper in the trampolines, and to
8556                          * change the called method to a dummy wrapper, and resolve that wrapper
8557                          * to the real method in mono_jit_compile_method ().
8558                          */
8559                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8560                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8561                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8562                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8563                         }
8564
8565                         /* Common call */
8566                         INLINE_FAILURE ("call");
8567                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8568                                                                                           imt_arg, vtable_arg);
8569
8570                         if (tail_call) {
8571                                 link_bblock (cfg, bblock, end_bblock);                  
8572                                 start_new_bblock = 1;
8573
8574                                 // FIXME: Eliminate unreachable epilogs
8575
8576                                 /*
8577                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8578                                  * only reachable from this call.
8579                                  */
8580                                 GET_BBLOCK (cfg, tblock, ip + 5);
8581                                 if (tblock == bblock || tblock->in_count == 0)
8582                                         skip_ret = TRUE;
8583                                 push_res = FALSE;
8584                         }
8585
8586                         call_end:
8587
8588                         /* End of call, INS should contain the result of the call, if any */
8589
8590                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8591                                 g_assert (ins);
8592                                 if (emit_widen)
8593                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8594                                 else
8595                                         *sp++ = ins;
8596                         }
8597
8598                         if (keep_this_alive) {
8599                                 MonoInst *dummy_use;
8600
8601                                 /* See mono_emit_method_call_full () */
8602                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8603                         }
8604
8605                         CHECK_CFG_EXCEPTION;
8606
8607                         ip += 5;
8608                         if (skip_ret) {
8609                                 g_assert (*ip == CEE_RET);
8610                                 ip += 1;
8611                         }
8612                         ins_flag = 0;
8613                         constrained_call = NULL;
8614                         if (need_seq_point)
8615                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8616                         break;
8617                 }
8618                 case CEE_RET:
8619                         if (cfg->method != method) {
8620                                 /* return from inlined method */
8621                                 /* 
8622                                  * If in_count == 0, that means the ret is unreachable due to
8623                                  * being preceeded by a throw. In that case, inline_method () will
8624                                  * handle setting the return value 
8625                                  * (test case: test_0_inline_throw ()).
8626                                  */
8627                                 if (return_var && cfg->cbb->in_count) {
8628                                         MonoType *ret_type = mono_method_signature (method)->ret;
8629
8630                                         MonoInst *store;
8631                                         CHECK_STACK (1);
8632                                         --sp;
8633
8634                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8635                                                 UNVERIFIED;
8636
8637                                         //g_assert (returnvar != -1);
8638                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8639                                         cfg->ret_var_set = TRUE;
8640                                 } 
8641                         } else {
8642                                 if (cfg->lmf_var && cfg->cbb->in_count)
8643                                         emit_pop_lmf (cfg);
8644
8645                                 if (cfg->ret) {
8646                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8647
8648                                         if (seq_points && !sym_seq_points) {
8649                                                 /* 
8650                                                  * Place a seq point here too even through the IL stack is not
8651                                                  * empty, so a step over on
8652                                                  * call <FOO>
8653                                                  * ret
8654                                                  * will work correctly.
8655                                                  */
8656                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8657                                                 MONO_ADD_INS (cfg->cbb, ins);
8658                                         }
8659
8660                                         g_assert (!return_var);
8661                                         CHECK_STACK (1);
8662                                         --sp;
8663
8664                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8665                                                 UNVERIFIED;
8666
8667                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8668                                                 MonoInst *ret_addr;
8669
8670                                                 if (!cfg->vret_addr) {
8671                                                         MonoInst *ins;
8672
8673                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8674                                                 } else {
8675                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8676
8677                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8678                                                         ins->klass = mono_class_from_mono_type (ret_type);
8679                                                 }
8680                                         } else {
8681 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8682                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8683                                                         MonoInst *iargs [1];
8684                                                         MonoInst *conv;
8685
8686                                                         iargs [0] = *sp;
8687                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8688                                                         mono_arch_emit_setret (cfg, method, conv);
8689                                                 } else {
8690                                                         mono_arch_emit_setret (cfg, method, *sp);
8691                                                 }
8692 #else
8693                                                 mono_arch_emit_setret (cfg, method, *sp);
8694 #endif
8695                                         }
8696                                 }
8697                         }
8698                         if (sp != stack_start)
8699                                 UNVERIFIED;
8700                         MONO_INST_NEW (cfg, ins, OP_BR);
8701                         ip++;
8702                         ins->inst_target_bb = end_bblock;
8703                         MONO_ADD_INS (bblock, ins);
8704                         link_bblock (cfg, bblock, end_bblock);
8705                         start_new_bblock = 1;
8706                         break;
8707                 case CEE_BR_S:
8708                         CHECK_OPSIZE (2);
8709                         MONO_INST_NEW (cfg, ins, OP_BR);
8710                         ip++;
8711                         target = ip + 1 + (signed char)(*ip);
8712                         ++ip;
8713                         GET_BBLOCK (cfg, tblock, target);
8714                         link_bblock (cfg, bblock, tblock);
8715                         ins->inst_target_bb = tblock;
8716                         if (sp != stack_start) {
8717                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8718                                 sp = stack_start;
8719                                 CHECK_UNVERIFIABLE (cfg);
8720                         }
8721                         MONO_ADD_INS (bblock, ins);
8722                         start_new_bblock = 1;
8723                         inline_costs += BRANCH_COST;
8724                         break;
8725                 case CEE_BEQ_S:
8726                 case CEE_BGE_S:
8727                 case CEE_BGT_S:
8728                 case CEE_BLE_S:
8729                 case CEE_BLT_S:
8730                 case CEE_BNE_UN_S:
8731                 case CEE_BGE_UN_S:
8732                 case CEE_BGT_UN_S:
8733                 case CEE_BLE_UN_S:
8734                 case CEE_BLT_UN_S:
8735                         CHECK_OPSIZE (2);
8736                         CHECK_STACK (2);
8737                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8738                         ip++;
8739                         target = ip + 1 + *(signed char*)ip;
8740                         ip++;
8741
8742                         ADD_BINCOND (NULL);
8743
8744                         sp = stack_start;
8745                         inline_costs += BRANCH_COST;
8746                         break;
8747                 case CEE_BR:
8748                         CHECK_OPSIZE (5);
8749                         MONO_INST_NEW (cfg, ins, OP_BR);
8750                         ip++;
8751
8752                         target = ip + 4 + (gint32)read32(ip);
8753                         ip += 4;
8754                         GET_BBLOCK (cfg, tblock, target);
8755                         link_bblock (cfg, bblock, tblock);
8756                         ins->inst_target_bb = tblock;
8757                         if (sp != stack_start) {
8758                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8759                                 sp = stack_start;
8760                                 CHECK_UNVERIFIABLE (cfg);
8761                         }
8762
8763                         MONO_ADD_INS (bblock, ins);
8764
8765                         start_new_bblock = 1;
8766                         inline_costs += BRANCH_COST;
8767                         break;
8768                 case CEE_BRFALSE_S:
8769                 case CEE_BRTRUE_S:
8770                 case CEE_BRFALSE:
8771                 case CEE_BRTRUE: {
8772                         MonoInst *cmp;
8773                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8774                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8775                         guint32 opsize = is_short ? 1 : 4;
8776
8777                         CHECK_OPSIZE (opsize);
8778                         CHECK_STACK (1);
8779                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8780                                 UNVERIFIED;
8781                         ip ++;
8782                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8783                         ip += opsize;
8784
8785                         sp--;
8786
8787                         GET_BBLOCK (cfg, tblock, target);
8788                         link_bblock (cfg, bblock, tblock);
8789                         GET_BBLOCK (cfg, tblock, ip);
8790                         link_bblock (cfg, bblock, tblock);
8791
8792                         if (sp != stack_start) {
8793                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8794                                 CHECK_UNVERIFIABLE (cfg);
8795                         }
8796
8797                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8798                         cmp->sreg1 = sp [0]->dreg;
8799                         type_from_op (cmp, sp [0], NULL);
8800                         CHECK_TYPE (cmp);
8801
8802 #if SIZEOF_REGISTER == 4
8803                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8804                                 /* Convert it to OP_LCOMPARE */
8805                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8806                                 ins->type = STACK_I8;
8807                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8808                                 ins->inst_l = 0;
8809                                 MONO_ADD_INS (bblock, ins);
8810                                 cmp->opcode = OP_LCOMPARE;
8811                                 cmp->sreg2 = ins->dreg;
8812                         }
8813 #endif
8814                         MONO_ADD_INS (bblock, cmp);
8815
8816                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8817                         type_from_op (ins, sp [0], NULL);
8818                         MONO_ADD_INS (bblock, ins);
8819                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8820                         GET_BBLOCK (cfg, tblock, target);
8821                         ins->inst_true_bb = tblock;
8822                         GET_BBLOCK (cfg, tblock, ip);
8823                         ins->inst_false_bb = tblock;
8824                         start_new_bblock = 2;
8825
8826                         sp = stack_start;
8827                         inline_costs += BRANCH_COST;
8828                         break;
8829                 }
8830                 case CEE_BEQ:
8831                 case CEE_BGE:
8832                 case CEE_BGT:
8833                 case CEE_BLE:
8834                 case CEE_BLT:
8835                 case CEE_BNE_UN:
8836                 case CEE_BGE_UN:
8837                 case CEE_BGT_UN:
8838                 case CEE_BLE_UN:
8839                 case CEE_BLT_UN:
8840                         CHECK_OPSIZE (5);
8841                         CHECK_STACK (2);
8842                         MONO_INST_NEW (cfg, ins, *ip);
8843                         ip++;
8844                         target = ip + 4 + (gint32)read32(ip);
8845                         ip += 4;
8846
8847                         ADD_BINCOND (NULL);
8848
8849                         sp = stack_start;
8850                         inline_costs += BRANCH_COST;
8851                         break;
8852                 case CEE_SWITCH: {
8853                         MonoInst *src1;
8854                         MonoBasicBlock **targets;
8855                         MonoBasicBlock *default_bblock;
8856                         MonoJumpInfoBBTable *table;
8857                         int offset_reg = alloc_preg (cfg);
8858                         int target_reg = alloc_preg (cfg);
8859                         int table_reg = alloc_preg (cfg);
8860                         int sum_reg = alloc_preg (cfg);
8861                         gboolean use_op_switch;
8862
8863                         CHECK_OPSIZE (5);
8864                         CHECK_STACK (1);
8865                         n = read32 (ip + 1);
8866                         --sp;
8867                         src1 = sp [0];
8868                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8869                                 UNVERIFIED;
8870
8871                         ip += 5;
8872                         CHECK_OPSIZE (n * sizeof (guint32));
8873                         target = ip + n * sizeof (guint32);
8874
8875                         GET_BBLOCK (cfg, default_bblock, target);
8876                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8877
8878                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8879                         for (i = 0; i < n; ++i) {
8880                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8881                                 targets [i] = tblock;
8882                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8883                                 ip += 4;
8884                         }
8885
8886                         if (sp != stack_start) {
8887                                 /* 
8888                                  * Link the current bb with the targets as well, so handle_stack_args
8889                                  * will set their in_stack correctly.
8890                                  */
8891                                 link_bblock (cfg, bblock, default_bblock);
8892                                 for (i = 0; i < n; ++i)
8893                                         link_bblock (cfg, bblock, targets [i]);
8894
8895                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8896                                 sp = stack_start;
8897                                 CHECK_UNVERIFIABLE (cfg);
8898                         }
8899
8900                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8901                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8902                         bblock = cfg->cbb;
8903
8904                         for (i = 0; i < n; ++i)
8905                                 link_bblock (cfg, bblock, targets [i]);
8906
8907                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8908                         table->table = targets;
8909                         table->table_size = n;
8910
8911                         use_op_switch = FALSE;
8912 #ifdef TARGET_ARM
8913                         /* ARM implements SWITCH statements differently */
8914                         /* FIXME: Make it use the generic implementation */
8915                         if (!cfg->compile_aot)
8916                                 use_op_switch = TRUE;
8917 #endif
8918
8919                         if (COMPILE_LLVM (cfg))
8920                                 use_op_switch = TRUE;
8921
8922                         cfg->cbb->has_jump_table = 1;
8923
8924                         if (use_op_switch) {
8925                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8926                                 ins->sreg1 = src1->dreg;
8927                                 ins->inst_p0 = table;
8928                                 ins->inst_many_bb = targets;
8929                                 ins->klass = GUINT_TO_POINTER (n);
8930                                 MONO_ADD_INS (cfg->cbb, ins);
8931                         } else {
8932                                 if (sizeof (gpointer) == 8)
8933                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8934                                 else
8935                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8936
8937 #if SIZEOF_REGISTER == 8
8938                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8939                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8940 #endif
8941
8942                                 if (cfg->compile_aot) {
8943                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8944                                 } else {
8945                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8946                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8947                                         ins->inst_p0 = table;
8948                                         ins->dreg = table_reg;
8949                                         MONO_ADD_INS (cfg->cbb, ins);
8950                                 }
8951
8952                                 /* FIXME: Use load_memindex */
8953                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8954                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8955                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8956                         }
8957                         start_new_bblock = 1;
8958                         inline_costs += (BRANCH_COST * 2);
8959                         break;
8960                 }
8961                 case CEE_LDIND_I1:
8962                 case CEE_LDIND_U1:
8963                 case CEE_LDIND_I2:
8964                 case CEE_LDIND_U2:
8965                 case CEE_LDIND_I4:
8966                 case CEE_LDIND_U4:
8967                 case CEE_LDIND_I8:
8968                 case CEE_LDIND_I:
8969                 case CEE_LDIND_R4:
8970                 case CEE_LDIND_R8:
8971                 case CEE_LDIND_REF:
8972                         CHECK_STACK (1);
8973                         --sp;
8974
8975                         switch (*ip) {
8976                         case CEE_LDIND_R4:
8977                         case CEE_LDIND_R8:
8978                                 dreg = alloc_freg (cfg);
8979                                 break;
8980                         case CEE_LDIND_I8:
8981                                 dreg = alloc_lreg (cfg);
8982                                 break;
8983                         case CEE_LDIND_REF:
8984                                 dreg = alloc_ireg_ref (cfg);
8985                                 break;
8986                         default:
8987                                 dreg = alloc_preg (cfg);
8988                         }
8989
8990                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
8991                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
8992                         ins->flags |= ins_flag;
8993                         ins_flag = 0;
8994                         MONO_ADD_INS (bblock, ins);
8995                         *sp++ = ins;
8996                         if (ins->flags & MONO_INST_VOLATILE) {
8997                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
8998                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8999                                 emit_memory_barrier (cfg, FullBarrier);
9000                         }
9001                         ++ip;
9002                         break;
9003                 case CEE_STIND_REF:
9004                 case CEE_STIND_I1:
9005                 case CEE_STIND_I2:
9006                 case CEE_STIND_I4:
9007                 case CEE_STIND_I8:
9008                 case CEE_STIND_R4:
9009                 case CEE_STIND_R8:
9010                 case CEE_STIND_I:
9011                         CHECK_STACK (2);
9012                         sp -= 2;
9013
9014                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9015                         ins->flags |= ins_flag;
9016                         ins_flag = 0;
9017
9018                         if (ins->flags & MONO_INST_VOLATILE) {
9019                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9020                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9021                                 emit_memory_barrier (cfg, FullBarrier);
9022                         }
9023
9024                         MONO_ADD_INS (bblock, ins);
9025
9026                         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)))
9027                                 emit_write_barrier (cfg, sp [0], sp [1]);
9028
9029                         inline_costs += 1;
9030                         ++ip;
9031                         break;
9032
9033                 case CEE_MUL:
9034                         CHECK_STACK (2);
9035
9036                         MONO_INST_NEW (cfg, ins, (*ip));
9037                         sp -= 2;
9038                         ins->sreg1 = sp [0]->dreg;
9039                         ins->sreg2 = sp [1]->dreg;
9040                         type_from_op (ins, sp [0], sp [1]);
9041                         CHECK_TYPE (ins);
9042                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9043
9044                         /* Use the immediate opcodes if possible */
9045                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9046                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9047                                 if (imm_opcode != -1) {
9048                                         ins->opcode = imm_opcode;
9049                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9050                                         ins->sreg2 = -1;
9051
9052                                         sp [1]->opcode = OP_NOP;
9053                                 }
9054                         }
9055
9056                         MONO_ADD_INS ((cfg)->cbb, (ins));
9057
9058                         *sp++ = mono_decompose_opcode (cfg, ins);
9059                         ip++;
9060                         break;
9061                 case CEE_ADD:
9062                 case CEE_SUB:
9063                 case CEE_DIV:
9064                 case CEE_DIV_UN:
9065                 case CEE_REM:
9066                 case CEE_REM_UN:
9067                 case CEE_AND:
9068                 case CEE_OR:
9069                 case CEE_XOR:
9070                 case CEE_SHL:
9071                 case CEE_SHR:
9072                 case CEE_SHR_UN:
9073                         CHECK_STACK (2);
9074
9075                         MONO_INST_NEW (cfg, ins, (*ip));
9076                         sp -= 2;
9077                         ins->sreg1 = sp [0]->dreg;
9078                         ins->sreg2 = sp [1]->dreg;
9079                         type_from_op (ins, sp [0], sp [1]);
9080                         CHECK_TYPE (ins);
9081                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9082                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9083
9084                         /* FIXME: Pass opcode to is_inst_imm */
9085
9086                         /* Use the immediate opcodes if possible */
9087                         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)) {
9088                                 int imm_opcode;
9089
9090                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9091 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9092                                 /* Keep emulated opcodes which are optimized away later */
9093                                 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) {
9094                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9095                                 }
9096 #endif
9097                                 if (imm_opcode != -1) {
9098                                         ins->opcode = imm_opcode;
9099                                         if (sp [1]->opcode == OP_I8CONST) {
9100 #if SIZEOF_REGISTER == 8
9101                                                 ins->inst_imm = sp [1]->inst_l;
9102 #else
9103                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9104                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9105 #endif
9106                                         }
9107                                         else
9108                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9109                                         ins->sreg2 = -1;
9110
9111                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9112                                         if (sp [1]->next == NULL)
9113                                                 sp [1]->opcode = OP_NOP;
9114                                 }
9115                         }
9116                         MONO_ADD_INS ((cfg)->cbb, (ins));
9117
9118                         *sp++ = mono_decompose_opcode (cfg, ins);
9119                         ip++;
9120                         break;
9121                 case CEE_NEG:
9122                 case CEE_NOT:
9123                 case CEE_CONV_I1:
9124                 case CEE_CONV_I2:
9125                 case CEE_CONV_I4:
9126                 case CEE_CONV_R4:
9127                 case CEE_CONV_R8:
9128                 case CEE_CONV_U4:
9129                 case CEE_CONV_I8:
9130                 case CEE_CONV_U8:
9131                 case CEE_CONV_OVF_I8:
9132                 case CEE_CONV_OVF_U8:
9133                 case CEE_CONV_R_UN:
9134                         CHECK_STACK (1);
9135
9136                         /* Special case this earlier so we have long constants in the IR */
9137                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9138                                 int data = sp [-1]->inst_c0;
9139                                 sp [-1]->opcode = OP_I8CONST;
9140                                 sp [-1]->type = STACK_I8;
9141 #if SIZEOF_REGISTER == 8
9142                                 if ((*ip) == CEE_CONV_U8)
9143                                         sp [-1]->inst_c0 = (guint32)data;
9144                                 else
9145                                         sp [-1]->inst_c0 = data;
9146 #else
9147                                 sp [-1]->inst_ls_word = data;
9148                                 if ((*ip) == CEE_CONV_U8)
9149                                         sp [-1]->inst_ms_word = 0;
9150                                 else
9151                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9152 #endif
9153                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9154                         }
9155                         else {
9156                                 ADD_UNOP (*ip);
9157                         }
9158                         ip++;
9159                         break;
9160                 case CEE_CONV_OVF_I4:
9161                 case CEE_CONV_OVF_I1:
9162                 case CEE_CONV_OVF_I2:
9163                 case CEE_CONV_OVF_I:
9164                 case CEE_CONV_OVF_U:
9165                         CHECK_STACK (1);
9166
9167                         if (sp [-1]->type == STACK_R8) {
9168                                 ADD_UNOP (CEE_CONV_OVF_I8);
9169                                 ADD_UNOP (*ip);
9170                         } else {
9171                                 ADD_UNOP (*ip);
9172                         }
9173                         ip++;
9174                         break;
9175                 case CEE_CONV_OVF_U1:
9176                 case CEE_CONV_OVF_U2:
9177                 case CEE_CONV_OVF_U4:
9178                         CHECK_STACK (1);
9179
9180                         if (sp [-1]->type == STACK_R8) {
9181                                 ADD_UNOP (CEE_CONV_OVF_U8);
9182                                 ADD_UNOP (*ip);
9183                         } else {
9184                                 ADD_UNOP (*ip);
9185                         }
9186                         ip++;
9187                         break;
9188                 case CEE_CONV_OVF_I1_UN:
9189                 case CEE_CONV_OVF_I2_UN:
9190                 case CEE_CONV_OVF_I4_UN:
9191                 case CEE_CONV_OVF_I8_UN:
9192                 case CEE_CONV_OVF_U1_UN:
9193                 case CEE_CONV_OVF_U2_UN:
9194                 case CEE_CONV_OVF_U4_UN:
9195                 case CEE_CONV_OVF_U8_UN:
9196                 case CEE_CONV_OVF_I_UN:
9197                 case CEE_CONV_OVF_U_UN:
9198                 case CEE_CONV_U2:
9199                 case CEE_CONV_U1:
9200                 case CEE_CONV_I:
9201                 case CEE_CONV_U:
9202                         CHECK_STACK (1);
9203                         ADD_UNOP (*ip);
9204                         CHECK_CFG_EXCEPTION;
9205                         ip++;
9206                         break;
9207                 case CEE_ADD_OVF:
9208                 case CEE_ADD_OVF_UN:
9209                 case CEE_MUL_OVF:
9210                 case CEE_MUL_OVF_UN:
9211                 case CEE_SUB_OVF:
9212                 case CEE_SUB_OVF_UN:
9213                         CHECK_STACK (2);
9214                         ADD_BINOP (*ip);
9215                         ip++;
9216                         break;
9217                 case CEE_CPOBJ:
9218                         GSHAREDVT_FAILURE (*ip);
9219                         CHECK_OPSIZE (5);
9220                         CHECK_STACK (2);
9221                         token = read32 (ip + 1);
9222                         klass = mini_get_class (method, token, generic_context);
9223                         CHECK_TYPELOAD (klass);
9224                         sp -= 2;
9225                         if (generic_class_is_reference_type (cfg, klass)) {
9226                                 MonoInst *store, *load;
9227                                 int dreg = alloc_ireg_ref (cfg);
9228
9229                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9230                                 load->flags |= ins_flag;
9231                                 MONO_ADD_INS (cfg->cbb, load);
9232
9233                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9234                                 store->flags |= ins_flag;
9235                                 MONO_ADD_INS (cfg->cbb, store);
9236
9237                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9238                                         emit_write_barrier (cfg, sp [0], sp [1]);
9239                         } else {
9240                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9241                         }
9242                         ins_flag = 0;
9243                         ip += 5;
9244                         break;
9245                 case CEE_LDOBJ: {
9246                         int loc_index = -1;
9247                         int stloc_len = 0;
9248
9249                         CHECK_OPSIZE (5);
9250                         CHECK_STACK (1);
9251                         --sp;
9252                         token = read32 (ip + 1);
9253                         klass = mini_get_class (method, token, generic_context);
9254                         CHECK_TYPELOAD (klass);
9255
9256                         /* Optimize the common ldobj+stloc combination */
9257                         switch (ip [5]) {
9258                         case CEE_STLOC_S:
9259                                 loc_index = ip [6];
9260                                 stloc_len = 2;
9261                                 break;
9262                         case CEE_STLOC_0:
9263                         case CEE_STLOC_1:
9264                         case CEE_STLOC_2:
9265                         case CEE_STLOC_3:
9266                                 loc_index = ip [5] - CEE_STLOC_0;
9267                                 stloc_len = 1;
9268                                 break;
9269                         default:
9270                                 break;
9271                         }
9272
9273                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9274                                 CHECK_LOCAL (loc_index);
9275
9276                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9277                                 ins->dreg = cfg->locals [loc_index]->dreg;
9278                                 ip += 5;
9279                                 ip += stloc_len;
9280                                 break;
9281                         }
9282
9283                         /* Optimize the ldobj+stobj combination */
9284                         /* The reference case ends up being a load+store anyway */
9285                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9286                                 CHECK_STACK (1);
9287
9288                                 sp --;
9289
9290                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9291
9292                                 ip += 5 + 5;
9293                                 ins_flag = 0;
9294                                 break;
9295                         }
9296
9297                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9298                         *sp++ = ins;
9299
9300                         ip += 5;
9301                         ins_flag = 0;
9302                         inline_costs += 1;
9303                         break;
9304                 }
9305                 case CEE_LDSTR:
9306                         CHECK_STACK_OVF (1);
9307                         CHECK_OPSIZE (5);
9308                         n = read32 (ip + 1);
9309
9310                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9311                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9312                                 ins->type = STACK_OBJ;
9313                                 *sp = ins;
9314                         }
9315                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9316                                 MonoInst *iargs [1];
9317
9318                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9319                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9320                         } else {
9321                                 if (cfg->opt & MONO_OPT_SHARED) {
9322                                         MonoInst *iargs [3];
9323
9324                                         if (cfg->compile_aot) {
9325                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9326                                         }
9327                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9328                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9329                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9330                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9331                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9332                                 } else {
9333                                         if (bblock->out_of_line) {
9334                                                 MonoInst *iargs [2];
9335
9336                                                 if (image == mono_defaults.corlib) {
9337                                                         /* 
9338                                                          * Avoid relocations in AOT and save some space by using a 
9339                                                          * version of helper_ldstr specialized to mscorlib.
9340                                                          */
9341                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9342                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9343                                                 } else {
9344                                                         /* Avoid creating the string object */
9345                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9346                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9347                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9348                                                 }
9349                                         } 
9350                                         else
9351                                         if (cfg->compile_aot) {
9352                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9353                                                 *sp = ins;
9354                                                 MONO_ADD_INS (bblock, ins);
9355                                         } 
9356                                         else {
9357                                                 NEW_PCONST (cfg, ins, NULL);
9358                                                 ins->type = STACK_OBJ;
9359                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9360                                                 if (!ins->inst_p0)
9361                                                         OUT_OF_MEMORY_FAILURE;
9362
9363                                                 *sp = ins;
9364                                                 MONO_ADD_INS (bblock, ins);
9365                                         }
9366                                 }
9367                         }
9368
9369                         sp++;
9370                         ip += 5;
9371                         break;
9372                 case CEE_NEWOBJ: {
9373                         MonoInst *iargs [2];
9374                         MonoMethodSignature *fsig;
9375                         MonoInst this_ins;
9376                         MonoInst *alloc;
9377                         MonoInst *vtable_arg = NULL;
9378
9379                         CHECK_OPSIZE (5);
9380                         token = read32 (ip + 1);
9381                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9382                         if (!cmethod || mono_loader_get_last_error ())
9383                                 LOAD_ERROR;
9384                         fsig = mono_method_get_signature (cmethod, image, token);
9385                         if (!fsig)
9386                                 LOAD_ERROR;
9387
9388                         mono_save_token_info (cfg, image, token, cmethod);
9389
9390                         if (!mono_class_init (cmethod->klass))
9391                                 TYPE_LOAD_ERROR (cmethod->klass);
9392
9393                         context_used = mini_method_check_context_used (cfg, cmethod);
9394
9395                         if (mono_security_cas_enabled ()) {
9396                                 if (check_linkdemand (cfg, method, cmethod))
9397                                         INLINE_FAILURE ("linkdemand");
9398                                 CHECK_CFG_EXCEPTION;
9399                         } else if (mono_security_core_clr_enabled ()) {
9400                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9401                         }
9402
9403                         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)) {
9404                                 emit_generic_class_init (cfg, cmethod->klass);
9405                                 CHECK_TYPELOAD (cmethod->klass);
9406                         }
9407
9408                         /*
9409                         if (cfg->gsharedvt) {
9410                                 if (mini_is_gsharedvt_variable_signature (sig))
9411                                         GSHAREDVT_FAILURE (*ip);
9412                         }
9413                         */
9414
9415                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9416                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9417                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9418                                         mono_class_vtable (cfg->domain, cmethod->klass);
9419                                         CHECK_TYPELOAD (cmethod->klass);
9420
9421                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9422                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9423                                 } else {
9424                                         if (context_used) {
9425                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9426                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9427                                         } else {
9428                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9429
9430                                                 CHECK_TYPELOAD (cmethod->klass);
9431                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9432                                         }
9433                                 }
9434                         }
9435
9436                         n = fsig->param_count;
9437                         CHECK_STACK (n);
9438
9439                         /* 
9440                          * Generate smaller code for the common newobj <exception> instruction in
9441                          * argument checking code.
9442                          */
9443                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9444                                 is_exception_class (cmethod->klass) && n <= 2 &&
9445                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9446                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9447                                 MonoInst *iargs [3];
9448
9449                                 g_assert (!vtable_arg);
9450
9451                                 sp -= n;
9452
9453                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9454                                 switch (n) {
9455                                 case 0:
9456                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9457                                         break;
9458                                 case 1:
9459                                         iargs [1] = sp [0];
9460                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9461                                         break;
9462                                 case 2:
9463                                         iargs [1] = sp [0];
9464                                         iargs [2] = sp [1];
9465                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9466                                         break;
9467                                 default:
9468                                         g_assert_not_reached ();
9469                                 }
9470
9471                                 ip += 5;
9472                                 inline_costs += 5;
9473                                 break;
9474                         }
9475
9476                         /* move the args to allow room for 'this' in the first position */
9477                         while (n--) {
9478                                 --sp;
9479                                 sp [1] = sp [0];
9480                         }
9481
9482                         /* check_call_signature () requires sp[0] to be set */
9483                         this_ins.type = STACK_OBJ;
9484                         sp [0] = &this_ins;
9485                         if (check_call_signature (cfg, fsig, sp))
9486                                 UNVERIFIED;
9487
9488                         iargs [0] = NULL;
9489
9490                         if (mini_class_is_system_array (cmethod->klass)) {
9491                                 g_assert (!vtable_arg);
9492
9493                                 *sp = emit_get_rgctx_method (cfg, context_used,
9494                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9495
9496                                 /* Avoid varargs in the common case */
9497                                 if (fsig->param_count == 1)
9498                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9499                                 else if (fsig->param_count == 2)
9500                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9501                                 else if (fsig->param_count == 3)
9502                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9503                                 else if (fsig->param_count == 4)
9504                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9505                                 else
9506                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9507                         } else if (cmethod->string_ctor) {
9508                                 g_assert (!context_used);
9509                                 g_assert (!vtable_arg);
9510                                 /* we simply pass a null pointer */
9511                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9512                                 /* now call the string ctor */
9513                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9514                         } else {
9515                                 MonoInst* callvirt_this_arg = NULL;
9516                                 
9517                                 if (cmethod->klass->valuetype) {
9518                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9519                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9520                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9521
9522                                         alloc = NULL;
9523
9524                                         /* 
9525                                          * The code generated by mini_emit_virtual_call () expects
9526                                          * iargs [0] to be a boxed instance, but luckily the vcall
9527                                          * will be transformed into a normal call there.
9528                                          */
9529                                 } else if (context_used) {
9530                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9531                                         *sp = alloc;
9532                                 } else {
9533                                         MonoVTable *vtable = NULL;
9534
9535                                         if (!cfg->compile_aot)
9536                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9537                                         CHECK_TYPELOAD (cmethod->klass);
9538
9539                                         /*
9540                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9541                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9542                                          * As a workaround, we call class cctors before allocating objects.
9543                                          */
9544                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9545                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9546                                                 if (cfg->verbose_level > 2)
9547                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9548                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9549                                         }
9550
9551                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9552                                         *sp = alloc;
9553                                 }
9554                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9555
9556                                 if (alloc)
9557                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9558
9559                                 /* Now call the actual ctor */
9560                                 /* Avoid virtual calls to ctors if possible */
9561                                 if (mono_class_is_marshalbyref (cmethod->klass))
9562                                         callvirt_this_arg = sp [0];
9563
9564
9565                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9566                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9567                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9568                                                 *sp = ins;
9569                                                 sp++;
9570                                         }
9571
9572                                         CHECK_CFG_EXCEPTION;
9573                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9574                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9575                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9576                                     !g_list_find (dont_inline, cmethod)) {
9577                                         int costs;
9578
9579                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9580                                                 cfg->real_offset += 5;
9581                                                 bblock = cfg->cbb;
9582
9583                                                 inline_costs += costs - 5;
9584                                         } else {
9585                                                 INLINE_FAILURE ("inline failure");
9586                                                 // FIXME-VT: Clean this up
9587                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9588                                                         GSHAREDVT_FAILURE(*ip);
9589                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9590                                         }
9591                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9592                                         MonoInst *addr;
9593
9594                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9595                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9596                                 } else if (context_used &&
9597                                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
9598                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
9599                                         MonoInst *cmethod_addr;
9600
9601                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9602                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9603
9604                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9605                                 } else {
9606                                         INLINE_FAILURE ("ctor call");
9607                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9608                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9609                                 }
9610                         }
9611
9612                         if (alloc == NULL) {
9613                                 /* Valuetype */
9614                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9615                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9616                                 *sp++= ins;
9617                         }
9618                         else
9619                                 *sp++ = alloc;
9620                         
9621                         ip += 5;
9622                         inline_costs += 5;
9623                         break;
9624                 }
9625                 case CEE_CASTCLASS:
9626                         CHECK_STACK (1);
9627                         --sp;
9628                         CHECK_OPSIZE (5);
9629                         token = read32 (ip + 1);
9630                         klass = mini_get_class (method, token, generic_context);
9631                         CHECK_TYPELOAD (klass);
9632                         if (sp [0]->type != STACK_OBJ)
9633                                 UNVERIFIED;
9634
9635                         context_used = mini_class_check_context_used (cfg, klass);
9636
9637                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9638                                 MonoInst *args [3];
9639
9640                                 /* obj */
9641                                 args [0] = *sp;
9642
9643                                 /* klass */
9644                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9645
9646                                 /* inline cache*/
9647                                 if (cfg->compile_aot)
9648                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9649                                 else
9650                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9651
9652                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9653
9654                                 *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9655                                 ip += 5;
9656                                 inline_costs += 2;
9657                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9658                                 MonoMethod *mono_castclass;
9659                                 MonoInst *iargs [1];
9660                                 int costs;
9661
9662                                 mono_castclass = mono_marshal_get_castclass (klass); 
9663                                 iargs [0] = sp [0];
9664                                 
9665                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9666                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9667                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9668                                 reset_cast_details (cfg);
9669                                 CHECK_CFG_EXCEPTION;
9670                                 g_assert (costs > 0);
9671                                 
9672                                 ip += 5;
9673                                 cfg->real_offset += 5;
9674                                 bblock = cfg->cbb;
9675
9676                                 *sp++ = iargs [0];
9677
9678                                 inline_costs += costs;
9679                         }
9680                         else {
9681                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9682                                 CHECK_CFG_EXCEPTION;
9683                                 bblock = cfg->cbb;
9684                                 *sp ++ = ins;
9685                                 ip += 5;
9686                         }
9687                         break;
9688                 case CEE_ISINST: {
9689                         CHECK_STACK (1);
9690                         --sp;
9691                         CHECK_OPSIZE (5);
9692                         token = read32 (ip + 1);
9693                         klass = mini_get_class (method, token, generic_context);
9694                         CHECK_TYPELOAD (klass);
9695                         if (sp [0]->type != STACK_OBJ)
9696                                 UNVERIFIED;
9697  
9698                         context_used = mini_class_check_context_used (cfg, klass);
9699
9700                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9701                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9702                                 MonoInst *args [3];
9703
9704                                 /* obj */
9705                                 args [0] = *sp;
9706
9707                                 /* klass */
9708                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9709
9710                                 /* inline cache*/
9711                                 if (cfg->compile_aot)
9712                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9713                                 else
9714                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9715
9716                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9717                                 ip += 5;
9718                                 inline_costs += 2;
9719                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9720                                 MonoMethod *mono_isinst;
9721                                 MonoInst *iargs [1];
9722                                 int costs;
9723
9724                                 mono_isinst = mono_marshal_get_isinst (klass); 
9725                                 iargs [0] = sp [0];
9726
9727                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9728                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9729                                 CHECK_CFG_EXCEPTION;
9730                                 g_assert (costs > 0);
9731                                 
9732                                 ip += 5;
9733                                 cfg->real_offset += 5;
9734                                 bblock = cfg->cbb;
9735
9736                                 *sp++= iargs [0];
9737
9738                                 inline_costs += costs;
9739                         }
9740                         else {
9741                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9742                                 CHECK_CFG_EXCEPTION;
9743                                 bblock = cfg->cbb;
9744                                 *sp ++ = ins;
9745                                 ip += 5;
9746                         }
9747                         break;
9748                 }
9749                 case CEE_UNBOX_ANY: {
9750                         CHECK_STACK (1);
9751                         --sp;
9752                         CHECK_OPSIZE (5);
9753                         token = read32 (ip + 1);
9754                         klass = mini_get_class (method, token, generic_context);
9755                         CHECK_TYPELOAD (klass);
9756  
9757                         mono_save_token_info (cfg, image, token, klass);
9758
9759                         context_used = mini_class_check_context_used (cfg, klass);
9760
9761                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9762                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9763                                 sp ++;
9764
9765                                 ip += 5;
9766                                 inline_costs += 2;
9767                                 break;
9768                         }
9769
9770                         if (generic_class_is_reference_type (cfg, klass)) {
9771                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9772                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9773                                         MonoInst *args [3];
9774
9775                                         /* obj */
9776                                         args [0] = *sp;
9777
9778                                         /* klass */
9779                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9780
9781                                         /* inline cache*/
9782                                         /*FIXME AOT support*/
9783                                         if (cfg->compile_aot)
9784                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9785                                         else
9786                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9787
9788                                         /* The wrapper doesn't inline well so the bloat of inlining doesn't pay off. */
9789                                         *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9790                                         ip += 5;
9791                                         inline_costs += 2;
9792                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9793                                         MonoMethod *mono_castclass;
9794                                         MonoInst *iargs [1];
9795                                         int costs;
9796
9797                                         mono_castclass = mono_marshal_get_castclass (klass); 
9798                                         iargs [0] = sp [0];
9799
9800                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9801                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9802                                         CHECK_CFG_EXCEPTION;
9803                                         g_assert (costs > 0);
9804                                 
9805                                         ip += 5;
9806                                         cfg->real_offset += 5;
9807                                         bblock = cfg->cbb;
9808
9809                                         *sp++ = iargs [0];
9810                                         inline_costs += costs;
9811                                 } else {
9812                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9813                                         CHECK_CFG_EXCEPTION;
9814                                         bblock = cfg->cbb;
9815                                         *sp ++ = ins;
9816                                         ip += 5;
9817                                 }
9818                                 break;
9819                         }
9820
9821                         if (mono_class_is_nullable (klass)) {
9822                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9823                                 *sp++= ins;
9824                                 ip += 5;
9825                                 break;
9826                         }
9827
9828                         /* UNBOX */
9829                         ins = handle_unbox (cfg, klass, sp, context_used);
9830                         *sp = ins;
9831
9832                         ip += 5;
9833
9834                         /* LDOBJ */
9835                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9836                         *sp++ = ins;
9837
9838                         inline_costs += 2;
9839                         break;
9840                 }
9841                 case CEE_BOX: {
9842                         MonoInst *val;
9843
9844                         CHECK_STACK (1);
9845                         --sp;
9846                         val = *sp;
9847                         CHECK_OPSIZE (5);
9848                         token = read32 (ip + 1);
9849                         klass = mini_get_class (method, token, generic_context);
9850                         CHECK_TYPELOAD (klass);
9851
9852                         mono_save_token_info (cfg, image, token, klass);
9853
9854                         context_used = mini_class_check_context_used (cfg, klass);
9855
9856                         if (generic_class_is_reference_type (cfg, klass)) {
9857                                 *sp++ = val;
9858                                 ip += 5;
9859                                 break;
9860                         }
9861
9862                         if (klass == mono_defaults.void_class)
9863                                 UNVERIFIED;
9864                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9865                                 UNVERIFIED;
9866                         /* frequent check in generic code: box (struct), brtrue */
9867
9868                         // FIXME: LLVM can't handle the inconsistent bb linking
9869                         if (!mono_class_is_nullable (klass) &&
9870                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9871                                 (ip [5] == CEE_BRTRUE || 
9872                                  ip [5] == CEE_BRTRUE_S ||
9873                                  ip [5] == CEE_BRFALSE ||
9874                                  ip [5] == CEE_BRFALSE_S)) {
9875                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9876                                 int dreg;
9877                                 MonoBasicBlock *true_bb, *false_bb;
9878
9879                                 ip += 5;
9880
9881                                 if (cfg->verbose_level > 3) {
9882                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9883                                         printf ("<box+brtrue opt>\n");
9884                                 }
9885
9886                                 switch (*ip) {
9887                                 case CEE_BRTRUE_S:
9888                                 case CEE_BRFALSE_S:
9889                                         CHECK_OPSIZE (2);
9890                                         ip++;
9891                                         target = ip + 1 + (signed char)(*ip);
9892                                         ip++;
9893                                         break;
9894                                 case CEE_BRTRUE:
9895                                 case CEE_BRFALSE:
9896                                         CHECK_OPSIZE (5);
9897                                         ip++;
9898                                         target = ip + 4 + (gint)(read32 (ip));
9899                                         ip += 4;
9900                                         break;
9901                                 default:
9902                                         g_assert_not_reached ();
9903                                 }
9904
9905                                 /* 
9906                                  * We need to link both bblocks, since it is needed for handling stack
9907                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9908                                  * Branching to only one of them would lead to inconsistencies, so
9909                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9910                                  */
9911                                 GET_BBLOCK (cfg, true_bb, target);
9912                                 GET_BBLOCK (cfg, false_bb, ip);
9913
9914                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9915                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9916
9917                                 if (sp != stack_start) {
9918                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9919                                         sp = stack_start;
9920                                         CHECK_UNVERIFIABLE (cfg);
9921                                 }
9922
9923                                 if (COMPILE_LLVM (cfg)) {
9924                                         dreg = alloc_ireg (cfg);
9925                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9926                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9927
9928                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9929                                 } else {
9930                                         /* The JIT can't eliminate the iconst+compare */
9931                                         MONO_INST_NEW (cfg, ins, OP_BR);
9932                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9933                                         MONO_ADD_INS (cfg->cbb, ins);
9934                                 }
9935
9936                                 start_new_bblock = 1;
9937                                 break;
9938                         }
9939
9940                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9941
9942                         CHECK_CFG_EXCEPTION;
9943                         ip += 5;
9944                         inline_costs += 1;
9945                         break;
9946                 }
9947                 case CEE_UNBOX: {
9948                         CHECK_STACK (1);
9949                         --sp;
9950                         CHECK_OPSIZE (5);
9951                         token = read32 (ip + 1);
9952                         klass = mini_get_class (method, token, generic_context);
9953                         CHECK_TYPELOAD (klass);
9954
9955                         mono_save_token_info (cfg, image, token, klass);
9956
9957                         context_used = mini_class_check_context_used (cfg, klass);
9958
9959                         if (mono_class_is_nullable (klass)) {
9960                                 MonoInst *val;
9961
9962                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9963                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9964
9965                                 *sp++= ins;
9966                         } else {
9967                                 ins = handle_unbox (cfg, klass, sp, context_used);
9968                                 *sp++ = ins;
9969                         }
9970                         ip += 5;
9971                         inline_costs += 2;
9972                         break;
9973                 }
9974                 case CEE_LDFLD:
9975                 case CEE_LDFLDA:
9976                 case CEE_STFLD:
9977                 case CEE_LDSFLD:
9978                 case CEE_LDSFLDA:
9979                 case CEE_STSFLD: {
9980                         MonoClassField *field;
9981 #ifndef DISABLE_REMOTING
9982                         int costs;
9983 #endif
9984                         guint foffset;
9985                         gboolean is_instance;
9986                         int op;
9987                         gpointer addr = NULL;
9988                         gboolean is_special_static;
9989                         MonoType *ftype;
9990                         MonoInst *store_val = NULL;
9991                         MonoInst *thread_ins;
9992
9993                         op = *ip;
9994                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
9995                         if (is_instance) {
9996                                 if (op == CEE_STFLD) {
9997                                         CHECK_STACK (2);
9998                                         sp -= 2;
9999                                         store_val = sp [1];
10000                                 } else {
10001                                         CHECK_STACK (1);
10002                                         --sp;
10003                                 }
10004                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10005                                         UNVERIFIED;
10006                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10007                                         UNVERIFIED;
10008                         } else {
10009                                 if (op == CEE_STSFLD) {
10010                                         CHECK_STACK (1);
10011                                         sp--;
10012                                         store_val = sp [0];
10013                                 }
10014                         }
10015
10016                         CHECK_OPSIZE (5);
10017                         token = read32 (ip + 1);
10018                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10019                                 field = mono_method_get_wrapper_data (method, token);
10020                                 klass = field->parent;
10021                         }
10022                         else {
10023                                 field = mono_field_from_token (image, token, &klass, generic_context);
10024                         }
10025                         if (!field)
10026                                 LOAD_ERROR;
10027                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10028                                 FIELD_ACCESS_FAILURE;
10029                         mono_class_init (klass);
10030
10031                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10032                                 UNVERIFIED;
10033
10034                         /* if the class is Critical then transparent code cannot access it's fields */
10035                         if (!is_instance && mono_security_core_clr_enabled ())
10036                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10037
10038                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10039                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10040                         if (mono_security_core_clr_enabled ())
10041                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10042                         */
10043
10044                         /*
10045                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10046                          * the static case.
10047                          */
10048                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10049                                 switch (op) {
10050                                 case CEE_LDFLD:
10051                                         op = CEE_LDSFLD;
10052                                         break;
10053                                 case CEE_STFLD:
10054                                         op = CEE_STSFLD;
10055                                         break;
10056                                 case CEE_LDFLDA:
10057                                         op = CEE_LDSFLDA;
10058                                         break;
10059                                 default:
10060                                         g_assert_not_reached ();
10061                                 }
10062                                 is_instance = FALSE;
10063                         }
10064
10065                         context_used = mini_class_check_context_used (cfg, klass);
10066
10067                         /* INSTANCE CASE */
10068
10069                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10070                         if (op == CEE_STFLD) {
10071                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10072                                         UNVERIFIED;
10073 #ifndef DISABLE_REMOTING
10074                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10075                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10076                                         MonoInst *iargs [5];
10077
10078                                         GSHAREDVT_FAILURE (op);
10079
10080                                         iargs [0] = sp [0];
10081                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10082                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10083                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10084                                                     field->offset);
10085                                         iargs [4] = sp [1];
10086
10087                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10088                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10089                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
10090                                                 CHECK_CFG_EXCEPTION;
10091                                                 g_assert (costs > 0);
10092                                                       
10093                                                 cfg->real_offset += 5;
10094                                                 bblock = cfg->cbb;
10095
10096                                                 inline_costs += costs;
10097                                         } else {
10098                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10099                                         }
10100                                 } else
10101 #endif
10102                                 {
10103                                         MonoInst *store;
10104
10105                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10106
10107                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10108                                                 MonoInst *offset_ins;
10109
10110                                                 context_used = mini_class_check_context_used (cfg, klass);
10111
10112                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10113                                                 dreg = alloc_ireg_mp (cfg);
10114                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10115                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10116                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10117                                         } else {
10118                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10119                                         }
10120                                         if (sp [0]->opcode != OP_LDADDR)
10121                                                 store->flags |= MONO_INST_FAULT;
10122
10123                                 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)) {
10124                                         /* insert call to write barrier */
10125                                         MonoInst *ptr;
10126                                         int dreg;
10127
10128                                         dreg = alloc_ireg_mp (cfg);
10129                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10130                                         emit_write_barrier (cfg, ptr, sp [1]);
10131                                 }
10132
10133                                         store->flags |= ins_flag;
10134                                 }
10135                                 ins_flag = 0;
10136                                 ip += 5;
10137                                 break;
10138                         }
10139
10140 #ifndef DISABLE_REMOTING
10141                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10142                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10143                                 MonoInst *iargs [4];
10144
10145                                 GSHAREDVT_FAILURE (op);
10146
10147                                 iargs [0] = sp [0];
10148                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10149                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10150                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10151                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10152                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10153                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
10154                                         CHECK_CFG_EXCEPTION;
10155                                         bblock = cfg->cbb;
10156                                         g_assert (costs > 0);
10157                                                       
10158                                         cfg->real_offset += 5;
10159
10160                                         *sp++ = iargs [0];
10161
10162                                         inline_costs += costs;
10163                                 } else {
10164                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10165                                         *sp++ = ins;
10166                                 }
10167                         } else 
10168 #endif
10169                         if (is_instance) {
10170                                 if (sp [0]->type == STACK_VTYPE) {
10171                                         MonoInst *var;
10172
10173                                         /* Have to compute the address of the variable */
10174
10175                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10176                                         if (!var)
10177                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10178                                         else
10179                                                 g_assert (var->klass == klass);
10180                                         
10181                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10182                                         sp [0] = ins;
10183                                 }
10184
10185                                 if (op == CEE_LDFLDA) {
10186                                         if (is_magic_tls_access (field)) {
10187                                                 GSHAREDVT_FAILURE (*ip);
10188                                                 ins = sp [0];
10189                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10190                                         } else {
10191                                                 if (sp [0]->type == STACK_OBJ) {
10192                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10193                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10194                                                 }
10195
10196                                                 dreg = alloc_ireg_mp (cfg);
10197
10198                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10199                                                         MonoInst *offset_ins;
10200
10201                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10202                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10203                                                 } else {
10204                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10205                                                 }
10206                                                 ins->klass = mono_class_from_mono_type (field->type);
10207                                                 ins->type = STACK_MP;
10208                                                 *sp++ = ins;
10209                                         }
10210                                 } else {
10211                                         MonoInst *load;
10212
10213                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10214
10215                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10216                                                 MonoInst *offset_ins;
10217
10218                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10219                                                 dreg = alloc_ireg_mp (cfg);
10220                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10221                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10222                                         } else {
10223                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10224                                         }
10225                                         load->flags |= ins_flag;
10226                                         if (sp [0]->opcode != OP_LDADDR)
10227                                                 load->flags |= MONO_INST_FAULT;
10228                                         *sp++ = load;
10229                                 }
10230                         }
10231
10232                         if (is_instance) {
10233                                 ins_flag = 0;
10234                                 ip += 5;
10235                                 break;
10236                         }
10237
10238                         /* STATIC CASE */
10239
10240                         /*
10241                          * We can only support shared generic static
10242                          * field access on architectures where the
10243                          * trampoline code has been extended to handle
10244                          * the generic class init.
10245                          */
10246 #ifndef MONO_ARCH_VTABLE_REG
10247                         GENERIC_SHARING_FAILURE (op);
10248 #endif
10249
10250                         context_used = mini_class_check_context_used (cfg, klass);
10251
10252                         ftype = mono_field_get_type (field);
10253
10254                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10255                                 UNVERIFIED;
10256
10257                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10258                          * to be called here.
10259                          */
10260                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10261                                 mono_class_vtable (cfg->domain, klass);
10262                                 CHECK_TYPELOAD (klass);
10263                         }
10264                         mono_domain_lock (cfg->domain);
10265                         if (cfg->domain->special_static_fields)
10266                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10267                         mono_domain_unlock (cfg->domain);
10268
10269                         is_special_static = mono_class_field_is_special_static (field);
10270
10271                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10272                                 thread_ins = mono_get_thread_intrinsic (cfg);
10273                         else
10274                                 thread_ins = NULL;
10275
10276                         /* Generate IR to compute the field address */
10277                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10278                                 /*
10279                                  * Fast access to TLS data
10280                                  * Inline version of get_thread_static_data () in
10281                                  * threads.c.
10282                                  */
10283                                 guint32 offset;
10284                                 int idx, static_data_reg, array_reg, dreg;
10285
10286                                 GSHAREDVT_FAILURE (op);
10287
10288                                 // offset &= 0x7fffffff;
10289                                 // idx = (offset >> 24) - 1;
10290                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10291                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10292                                 static_data_reg = alloc_ireg (cfg);
10293                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10294
10295                                 if (cfg->compile_aot) {
10296                                         int offset_reg, offset2_reg, idx_reg;
10297
10298                                         /* For TLS variables, this will return the TLS offset */
10299                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10300                                         offset_reg = ins->dreg;
10301                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10302                                         idx_reg = alloc_ireg (cfg);
10303                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10304                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10305                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10306                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10307                                         array_reg = alloc_ireg (cfg);
10308                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10309                                         offset2_reg = alloc_ireg (cfg);
10310                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10311                                         dreg = alloc_ireg (cfg);
10312                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10313                                 } else {
10314                                         offset = (gsize)addr & 0x7fffffff;
10315                                         idx = (offset >> 24) - 1;
10316
10317                                         array_reg = alloc_ireg (cfg);
10318                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10319                                         dreg = alloc_ireg (cfg);
10320                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10321                                 }
10322                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10323                                         (cfg->compile_aot && is_special_static) ||
10324                                         (context_used && is_special_static)) {
10325                                 MonoInst *iargs [2];
10326
10327                                 g_assert (field->parent);
10328                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10329                                 if (context_used) {
10330                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10331                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10332                                 } else {
10333                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10334                                 }
10335                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10336                         } else if (context_used) {
10337                                 MonoInst *static_data;
10338
10339                                 /*
10340                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10341                                         method->klass->name_space, method->klass->name, method->name,
10342                                         depth, field->offset);
10343                                 */
10344
10345                                 if (mono_class_needs_cctor_run (klass, method))
10346                                         emit_generic_class_init (cfg, klass);
10347
10348                                 /*
10349                                  * The pointer we're computing here is
10350                                  *
10351                                  *   super_info.static_data + field->offset
10352                                  */
10353                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10354                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10355
10356                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10357                                         MonoInst *offset_ins;
10358
10359                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10360                                         dreg = alloc_ireg_mp (cfg);
10361                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10362                                 } else if (field->offset == 0) {
10363                                         ins = static_data;
10364                                 } else {
10365                                         int addr_reg = mono_alloc_preg (cfg);
10366                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10367                                 }
10368                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10369                                 MonoInst *iargs [2];
10370
10371                                 g_assert (field->parent);
10372                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10373                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10374                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10375                         } else {
10376                                 MonoVTable *vtable = NULL;
10377
10378                                 if (!cfg->compile_aot)
10379                                         vtable = mono_class_vtable (cfg->domain, klass);
10380                                 CHECK_TYPELOAD (klass);
10381
10382                                 if (!addr) {
10383                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10384                                                 if (!(g_slist_find (class_inits, klass))) {
10385                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10386                                                         if (cfg->verbose_level > 2)
10387                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10388                                                         class_inits = g_slist_prepend (class_inits, klass);
10389                                                 }
10390                                         } else {
10391                                                 if (cfg->run_cctors) {
10392                                                         MonoException *ex;
10393                                                         /* This makes so that inline cannot trigger */
10394                                                         /* .cctors: too many apps depend on them */
10395                                                         /* running with a specific order... */
10396                                                         g_assert (vtable);
10397                                                         if (! vtable->initialized)
10398                                                                 INLINE_FAILURE ("class init");
10399                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10400                                                         if (ex) {
10401                                                                 set_exception_object (cfg, ex);
10402                                                                 goto exception_exit;
10403                                                         }
10404                                                 }
10405                                         }
10406                                         if (cfg->compile_aot)
10407                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10408                                         else {
10409                                                 g_assert (vtable);
10410                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10411                                                 g_assert (addr);
10412                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10413                                         }
10414                                 } else {
10415                                         MonoInst *iargs [1];
10416                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10417                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10418                                 }
10419                         }
10420
10421                         /* Generate IR to do the actual load/store operation */
10422
10423                         if (op == CEE_LDSFLDA) {
10424                                 ins->klass = mono_class_from_mono_type (ftype);
10425                                 ins->type = STACK_PTR;
10426                                 *sp++ = ins;
10427                         } else if (op == CEE_STSFLD) {
10428                                 MonoInst *store;
10429
10430                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10431                                 store->flags |= ins_flag;
10432                         } else {
10433                                 gboolean is_const = FALSE;
10434                                 MonoVTable *vtable = NULL;
10435                                 gpointer addr = NULL;
10436
10437                                 if (!context_used) {
10438                                         vtable = mono_class_vtable (cfg->domain, klass);
10439                                         CHECK_TYPELOAD (klass);
10440                                 }
10441                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10442                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10443                                         int ro_type = ftype->type;
10444                                         if (!addr)
10445                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10446                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10447                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10448                                         }
10449
10450                                         GSHAREDVT_FAILURE (op);
10451
10452                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10453                                         is_const = TRUE;
10454                                         switch (ro_type) {
10455                                         case MONO_TYPE_BOOLEAN:
10456                                         case MONO_TYPE_U1:
10457                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10458                                                 sp++;
10459                                                 break;
10460                                         case MONO_TYPE_I1:
10461                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10462                                                 sp++;
10463                                                 break;                                          
10464                                         case MONO_TYPE_CHAR:
10465                                         case MONO_TYPE_U2:
10466                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10467                                                 sp++;
10468                                                 break;
10469                                         case MONO_TYPE_I2:
10470                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10471                                                 sp++;
10472                                                 break;
10473                                                 break;
10474                                         case MONO_TYPE_I4:
10475                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10476                                                 sp++;
10477                                                 break;                                          
10478                                         case MONO_TYPE_U4:
10479                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10480                                                 sp++;
10481                                                 break;
10482                                         case MONO_TYPE_I:
10483                                         case MONO_TYPE_U:
10484                                         case MONO_TYPE_PTR:
10485                                         case MONO_TYPE_FNPTR:
10486                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10487                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10488                                                 sp++;
10489                                                 break;
10490                                         case MONO_TYPE_STRING:
10491                                         case MONO_TYPE_OBJECT:
10492                                         case MONO_TYPE_CLASS:
10493                                         case MONO_TYPE_SZARRAY:
10494                                         case MONO_TYPE_ARRAY:
10495                                                 if (!mono_gc_is_moving ()) {
10496                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10497                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10498                                                         sp++;
10499                                                 } else {
10500                                                         is_const = FALSE;
10501                                                 }
10502                                                 break;
10503                                         case MONO_TYPE_I8:
10504                                         case MONO_TYPE_U8:
10505                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10506                                                 sp++;
10507                                                 break;
10508                                         case MONO_TYPE_R4:
10509                                         case MONO_TYPE_R8:
10510                                         case MONO_TYPE_VALUETYPE:
10511                                         default:
10512                                                 is_const = FALSE;
10513                                                 break;
10514                                         }
10515                                 }
10516
10517                                 if (!is_const) {
10518                                         MonoInst *load;
10519
10520                                         CHECK_STACK_OVF (1);
10521
10522                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10523                                         load->flags |= ins_flag;
10524                                         ins_flag = 0;
10525                                         *sp++ = load;
10526                                 }
10527                         }
10528                         ins_flag = 0;
10529                         ip += 5;
10530                         break;
10531                 }
10532                 case CEE_STOBJ:
10533                         CHECK_STACK (2);
10534                         sp -= 2;
10535                         CHECK_OPSIZE (5);
10536                         token = read32 (ip + 1);
10537                         klass = mini_get_class (method, token, generic_context);
10538                         CHECK_TYPELOAD (klass);
10539                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10540                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10541                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10542                                         generic_class_is_reference_type (cfg, klass)) {
10543                                 /* insert call to write barrier */
10544                                 emit_write_barrier (cfg, sp [0], sp [1]);
10545                         }
10546                         ins_flag = 0;
10547                         ip += 5;
10548                         inline_costs += 1;
10549                         break;
10550
10551                         /*
10552                          * Array opcodes
10553                          */
10554                 case CEE_NEWARR: {
10555                         MonoInst *len_ins;
10556                         const char *data_ptr;
10557                         int data_size = 0;
10558                         guint32 field_token;
10559
10560                         CHECK_STACK (1);
10561                         --sp;
10562
10563                         CHECK_OPSIZE (5);
10564                         token = read32 (ip + 1);
10565
10566                         klass = mini_get_class (method, token, generic_context);
10567                         CHECK_TYPELOAD (klass);
10568
10569                         context_used = mini_class_check_context_used (cfg, klass);
10570
10571                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10572                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10573                                 ins->sreg1 = sp [0]->dreg;
10574                                 ins->type = STACK_I4;
10575                                 ins->dreg = alloc_ireg (cfg);
10576                                 MONO_ADD_INS (cfg->cbb, ins);
10577                                 *sp = mono_decompose_opcode (cfg, ins);
10578                         }
10579
10580                         if (context_used) {
10581                                 MonoInst *args [3];
10582                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10583                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10584
10585                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10586
10587                                 /* vtable */
10588                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10589                                         array_class, MONO_RGCTX_INFO_VTABLE);
10590                                 /* array len */
10591                                 args [1] = sp [0];
10592
10593                                 if (managed_alloc)
10594                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10595                                 else
10596                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10597                         } else {
10598                                 if (cfg->opt & MONO_OPT_SHARED) {
10599                                         /* Decompose now to avoid problems with references to the domainvar */
10600                                         MonoInst *iargs [3];
10601
10602                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10603                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10604                                         iargs [2] = sp [0];
10605
10606                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10607                                 } else {
10608                                         /* Decompose later since it is needed by abcrem */
10609                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10610                                         mono_class_vtable (cfg->domain, array_type);
10611                                         CHECK_TYPELOAD (array_type);
10612
10613                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10614                                         ins->dreg = alloc_ireg_ref (cfg);
10615                                         ins->sreg1 = sp [0]->dreg;
10616                                         ins->inst_newa_class = klass;
10617                                         ins->type = STACK_OBJ;
10618                                         ins->klass = array_type;
10619                                         MONO_ADD_INS (cfg->cbb, ins);
10620                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10621                                         cfg->cbb->has_array_access = TRUE;
10622
10623                                         /* Needed so mono_emit_load_get_addr () gets called */
10624                                         mono_get_got_var (cfg);
10625                                 }
10626                         }
10627
10628                         len_ins = sp [0];
10629                         ip += 5;
10630                         *sp++ = ins;
10631                         inline_costs += 1;
10632
10633                         /* 
10634                          * we inline/optimize the initialization sequence if possible.
10635                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10636                          * for small sizes open code the memcpy
10637                          * ensure the rva field is big enough
10638                          */
10639                         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))) {
10640                                 MonoMethod *memcpy_method = get_memcpy_method ();
10641                                 MonoInst *iargs [3];
10642                                 int add_reg = alloc_ireg_mp (cfg);
10643
10644                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10645                                 if (cfg->compile_aot) {
10646                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10647                                 } else {
10648                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10649                                 }
10650                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10651                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10652                                 ip += 11;
10653                         }
10654
10655                         break;
10656                 }
10657                 case CEE_LDLEN:
10658                         CHECK_STACK (1);
10659                         --sp;
10660                         if (sp [0]->type != STACK_OBJ)
10661                                 UNVERIFIED;
10662
10663                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10664                         ins->dreg = alloc_preg (cfg);
10665                         ins->sreg1 = sp [0]->dreg;
10666                         ins->type = STACK_I4;
10667                         /* This flag will be inherited by the decomposition */
10668                         ins->flags |= MONO_INST_FAULT;
10669                         MONO_ADD_INS (cfg->cbb, ins);
10670                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10671                         cfg->cbb->has_array_access = TRUE;
10672                         ip ++;
10673                         *sp++ = ins;
10674                         break;
10675                 case CEE_LDELEMA:
10676                         CHECK_STACK (2);
10677                         sp -= 2;
10678                         CHECK_OPSIZE (5);
10679                         if (sp [0]->type != STACK_OBJ)
10680                                 UNVERIFIED;
10681
10682                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10683
10684                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10685                         CHECK_TYPELOAD (klass);
10686                         /* we need to make sure that this array is exactly the type it needs
10687                          * to be for correctness. the wrappers are lax with their usage
10688                          * so we need to ignore them here
10689                          */
10690                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10691                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10692                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10693                                 CHECK_TYPELOAD (array_class);
10694                         }
10695
10696                         readonly = FALSE;
10697                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10698                         *sp++ = ins;
10699                         ip += 5;
10700                         break;
10701                 case CEE_LDELEM:
10702                 case CEE_LDELEM_I1:
10703                 case CEE_LDELEM_U1:
10704                 case CEE_LDELEM_I2:
10705                 case CEE_LDELEM_U2:
10706                 case CEE_LDELEM_I4:
10707                 case CEE_LDELEM_U4:
10708                 case CEE_LDELEM_I8:
10709                 case CEE_LDELEM_I:
10710                 case CEE_LDELEM_R4:
10711                 case CEE_LDELEM_R8:
10712                 case CEE_LDELEM_REF: {
10713                         MonoInst *addr;
10714
10715                         CHECK_STACK (2);
10716                         sp -= 2;
10717
10718                         if (*ip == CEE_LDELEM) {
10719                                 CHECK_OPSIZE (5);
10720                                 token = read32 (ip + 1);
10721                                 klass = mini_get_class (method, token, generic_context);
10722                                 CHECK_TYPELOAD (klass);
10723                                 mono_class_init (klass);
10724                         }
10725                         else
10726                                 klass = array_access_to_klass (*ip);
10727
10728                         if (sp [0]->type != STACK_OBJ)
10729                                 UNVERIFIED;
10730
10731                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10732
10733                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10734                                 // FIXME-VT: OP_ICONST optimization
10735                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10736                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10737                                 ins->opcode = OP_LOADV_MEMBASE;
10738                         } else if (sp [1]->opcode == OP_ICONST) {
10739                                 int array_reg = sp [0]->dreg;
10740                                 int index_reg = sp [1]->dreg;
10741                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10742
10743                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10744                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10745                         } else {
10746                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10747                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10748                         }
10749                         *sp++ = ins;
10750                         if (*ip == CEE_LDELEM)
10751                                 ip += 5;
10752                         else
10753                                 ++ip;
10754                         break;
10755                 }
10756                 case CEE_STELEM_I:
10757                 case CEE_STELEM_I1:
10758                 case CEE_STELEM_I2:
10759                 case CEE_STELEM_I4:
10760                 case CEE_STELEM_I8:
10761                 case CEE_STELEM_R4:
10762                 case CEE_STELEM_R8:
10763                 case CEE_STELEM_REF:
10764                 case CEE_STELEM: {
10765                         CHECK_STACK (3);
10766                         sp -= 3;
10767
10768                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10769
10770                         if (*ip == CEE_STELEM) {
10771                                 CHECK_OPSIZE (5);
10772                                 token = read32 (ip + 1);
10773                                 klass = mini_get_class (method, token, generic_context);
10774                                 CHECK_TYPELOAD (klass);
10775                                 mono_class_init (klass);
10776                         }
10777                         else
10778                                 klass = array_access_to_klass (*ip);
10779
10780                         if (sp [0]->type != STACK_OBJ)
10781                                 UNVERIFIED;
10782
10783                         emit_array_store (cfg, klass, sp, TRUE);
10784
10785                         if (*ip == CEE_STELEM)
10786                                 ip += 5;
10787                         else
10788                                 ++ip;
10789                         inline_costs += 1;
10790                         break;
10791                 }
10792                 case CEE_CKFINITE: {
10793                         CHECK_STACK (1);
10794                         --sp;
10795
10796                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10797                         ins->sreg1 = sp [0]->dreg;
10798                         ins->dreg = alloc_freg (cfg);
10799                         ins->type = STACK_R8;
10800                         MONO_ADD_INS (bblock, ins);
10801
10802                         *sp++ = mono_decompose_opcode (cfg, ins);
10803
10804                         ++ip;
10805                         break;
10806                 }
10807                 case CEE_REFANYVAL: {
10808                         MonoInst *src_var, *src;
10809
10810                         int klass_reg = alloc_preg (cfg);
10811                         int dreg = alloc_preg (cfg);
10812
10813                         GSHAREDVT_FAILURE (*ip);
10814
10815                         CHECK_STACK (1);
10816                         MONO_INST_NEW (cfg, ins, *ip);
10817                         --sp;
10818                         CHECK_OPSIZE (5);
10819                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10820                         CHECK_TYPELOAD (klass);
10821                         mono_class_init (klass);
10822
10823                         context_used = mini_class_check_context_used (cfg, klass);
10824
10825                         // FIXME:
10826                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10827                         if (!src_var)
10828                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10829                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10830                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10831
10832                         if (context_used) {
10833                                 MonoInst *klass_ins;
10834
10835                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10836                                                 klass, MONO_RGCTX_INFO_KLASS);
10837
10838                                 // FIXME:
10839                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10840                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10841                         } else {
10842                                 mini_emit_class_check (cfg, klass_reg, klass);
10843                         }
10844                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10845                         ins->type = STACK_MP;
10846                         *sp++ = ins;
10847                         ip += 5;
10848                         break;
10849                 }
10850                 case CEE_MKREFANY: {
10851                         MonoInst *loc, *addr;
10852
10853                         GSHAREDVT_FAILURE (*ip);
10854
10855                         CHECK_STACK (1);
10856                         MONO_INST_NEW (cfg, ins, *ip);
10857                         --sp;
10858                         CHECK_OPSIZE (5);
10859                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10860                         CHECK_TYPELOAD (klass);
10861                         mono_class_init (klass);
10862
10863                         context_used = mini_class_check_context_used (cfg, klass);
10864
10865                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10866                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10867
10868                         if (context_used) {
10869                                 MonoInst *const_ins;
10870                                 int type_reg = alloc_preg (cfg);
10871
10872                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10873                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10874                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10875                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10876                         } else if (cfg->compile_aot) {
10877                                 int const_reg = alloc_preg (cfg);
10878                                 int type_reg = alloc_preg (cfg);
10879
10880                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10881                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10882                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10883                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10884                         } else {
10885                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10886                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10887                         }
10888                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10889
10890                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10891                         ins->type = STACK_VTYPE;
10892                         ins->klass = mono_defaults.typed_reference_class;
10893                         *sp++ = ins;
10894                         ip += 5;
10895                         break;
10896                 }
10897                 case CEE_LDTOKEN: {
10898                         gpointer handle;
10899                         MonoClass *handle_class;
10900
10901                         CHECK_STACK_OVF (1);
10902
10903                         CHECK_OPSIZE (5);
10904                         n = read32 (ip + 1);
10905
10906                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10907                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10908                                 handle = mono_method_get_wrapper_data (method, n);
10909                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10910                                 if (handle_class == mono_defaults.typehandle_class)
10911                                         handle = &((MonoClass*)handle)->byval_arg;
10912                         }
10913                         else {
10914                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10915                         }
10916                         if (!handle)
10917                                 LOAD_ERROR;
10918                         mono_class_init (handle_class);
10919                         if (cfg->generic_sharing_context) {
10920                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10921                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10922                                         /* This case handles ldtoken
10923                                            of an open type, like for
10924                                            typeof(Gen<>). */
10925                                         context_used = 0;
10926                                 } else if (handle_class == mono_defaults.typehandle_class) {
10927                                         /* If we get a MONO_TYPE_CLASS
10928                                            then we need to provide the
10929                                            open type, not an
10930                                            instantiation of it. */
10931                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10932                                                 context_used = 0;
10933                                         else
10934                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10935                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10936                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10937                                 else if (handle_class == mono_defaults.methodhandle_class)
10938                                         context_used = mini_method_check_context_used (cfg, handle);
10939                                 else
10940                                         g_assert_not_reached ();
10941                         }
10942
10943                         if ((cfg->opt & MONO_OPT_SHARED) &&
10944                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10945                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10946                                 MonoInst *addr, *vtvar, *iargs [3];
10947                                 int method_context_used;
10948
10949                                 method_context_used = mini_method_check_context_used (cfg, method);
10950
10951                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10952
10953                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10954                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10955                                 if (method_context_used) {
10956                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10957                                                 method, MONO_RGCTX_INFO_METHOD);
10958                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10959                                 } else {
10960                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10961                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10962                                 }
10963                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10964
10965                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10966
10967                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10968                         } else {
10969                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10970                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10971                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10972                                         (cmethod->klass == mono_defaults.systemtype_class) &&
10973                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10974                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10975
10976                                         mono_class_init (tclass);
10977                                         if (context_used) {
10978                                                 ins = emit_get_rgctx_klass (cfg, context_used,
10979                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
10980                                         } else if (cfg->compile_aot) {
10981                                                 if (method->wrapper_type) {
10982                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
10983                                                                 /* Special case for static synchronized wrappers */
10984                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
10985                                                         } else {
10986                                                                 /* FIXME: n is not a normal token */
10987                                                                 DISABLE_AOT (cfg);
10988                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
10989                                                         }
10990                                                 } else {
10991                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
10992                                                 }
10993                                         } else {
10994                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
10995                                         }
10996                                         ins->type = STACK_OBJ;
10997                                         ins->klass = cmethod->klass;
10998                                         ip += 5;
10999                                 } else {
11000                                         MonoInst *addr, *vtvar;
11001
11002                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11003
11004                                         if (context_used) {
11005                                                 if (handle_class == mono_defaults.typehandle_class) {
11006                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11007                                                                         mono_class_from_mono_type (handle),
11008                                                                         MONO_RGCTX_INFO_TYPE);
11009                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11010                                                         ins = emit_get_rgctx_method (cfg, context_used,
11011                                                                         handle, MONO_RGCTX_INFO_METHOD);
11012                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11013                                                         ins = emit_get_rgctx_field (cfg, context_used,
11014                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11015                                                 } else {
11016                                                         g_assert_not_reached ();
11017                                                 }
11018                                         } else if (cfg->compile_aot) {
11019                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11020                                         } else {
11021                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11022                                         }
11023                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11024                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11025                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11026                                 }
11027                         }
11028
11029                         *sp++ = ins;
11030                         ip += 5;
11031                         break;
11032                 }
11033                 case CEE_THROW:
11034                         CHECK_STACK (1);
11035                         MONO_INST_NEW (cfg, ins, OP_THROW);
11036                         --sp;
11037                         ins->sreg1 = sp [0]->dreg;
11038                         ip++;
11039                         bblock->out_of_line = TRUE;
11040                         MONO_ADD_INS (bblock, ins);
11041                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11042                         MONO_ADD_INS (bblock, ins);
11043                         sp = stack_start;
11044                         
11045                         link_bblock (cfg, bblock, end_bblock);
11046                         start_new_bblock = 1;
11047                         break;
11048                 case CEE_ENDFINALLY:
11049                         /* mono_save_seq_point_info () depends on this */
11050                         if (sp != stack_start)
11051                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11052                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11053                         MONO_ADD_INS (bblock, ins);
11054                         ip++;
11055                         start_new_bblock = 1;
11056
11057                         /*
11058                          * Control will leave the method so empty the stack, otherwise
11059                          * the next basic block will start with a nonempty stack.
11060                          */
11061                         while (sp != stack_start) {
11062                                 sp--;
11063                         }
11064                         break;
11065                 case CEE_LEAVE:
11066                 case CEE_LEAVE_S: {
11067                         GList *handlers;
11068
11069                         if (*ip == CEE_LEAVE) {
11070                                 CHECK_OPSIZE (5);
11071                                 target = ip + 5 + (gint32)read32(ip + 1);
11072                         } else {
11073                                 CHECK_OPSIZE (2);
11074                                 target = ip + 2 + (signed char)(ip [1]);
11075                         }
11076
11077                         /* empty the stack */
11078                         while (sp != stack_start) {
11079                                 sp--;
11080                         }
11081
11082                         /* 
11083                          * If this leave statement is in a catch block, check for a
11084                          * pending exception, and rethrow it if necessary.
11085                          * We avoid doing this in runtime invoke wrappers, since those are called
11086                          * by native code which excepts the wrapper to catch all exceptions.
11087                          */
11088                         for (i = 0; i < header->num_clauses; ++i) {
11089                                 MonoExceptionClause *clause = &header->clauses [i];
11090
11091                                 /* 
11092                                  * Use <= in the final comparison to handle clauses with multiple
11093                                  * leave statements, like in bug #78024.
11094                                  * The ordering of the exception clauses guarantees that we find the
11095                                  * innermost clause.
11096                                  */
11097                                 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) {
11098                                         MonoInst *exc_ins;
11099                                         MonoBasicBlock *dont_throw;
11100
11101                                         /*
11102                                           MonoInst *load;
11103
11104                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11105                                         */
11106
11107                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11108
11109                                         NEW_BBLOCK (cfg, dont_throw);
11110
11111                                         /*
11112                                          * Currently, we always rethrow the abort exception, despite the 
11113                                          * fact that this is not correct. See thread6.cs for an example. 
11114                                          * But propagating the abort exception is more important than 
11115                                          * getting the sematics right.
11116                                          */
11117                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11118                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11119                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11120
11121                                         MONO_START_BB (cfg, dont_throw);
11122                                         bblock = cfg->cbb;
11123                                 }
11124                         }
11125
11126                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11127                                 GList *tmp;
11128                                 MonoExceptionClause *clause;
11129
11130                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11131                                         clause = tmp->data;
11132                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11133                                         g_assert (tblock);
11134                                         link_bblock (cfg, bblock, tblock);
11135                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11136                                         ins->inst_target_bb = tblock;
11137                                         ins->inst_eh_block = clause;
11138                                         MONO_ADD_INS (bblock, ins);
11139                                         bblock->has_call_handler = 1;
11140                                         if (COMPILE_LLVM (cfg)) {
11141                                                 MonoBasicBlock *target_bb;
11142
11143                                                 /* 
11144                                                  * Link the finally bblock with the target, since it will
11145                                                  * conceptually branch there.
11146                                                  * FIXME: Have to link the bblock containing the endfinally.
11147                                                  */
11148                                                 GET_BBLOCK (cfg, target_bb, target);
11149                                                 link_bblock (cfg, tblock, target_bb);
11150                                         }
11151                                 }
11152                                 g_list_free (handlers);
11153                         } 
11154
11155                         MONO_INST_NEW (cfg, ins, OP_BR);
11156                         MONO_ADD_INS (bblock, ins);
11157                         GET_BBLOCK (cfg, tblock, target);
11158                         link_bblock (cfg, bblock, tblock);
11159                         ins->inst_target_bb = tblock;
11160                         start_new_bblock = 1;
11161
11162                         if (*ip == CEE_LEAVE)
11163                                 ip += 5;
11164                         else
11165                                 ip += 2;
11166
11167                         break;
11168                 }
11169
11170                         /*
11171                          * Mono specific opcodes
11172                          */
11173                 case MONO_CUSTOM_PREFIX: {
11174
11175                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11176
11177                         CHECK_OPSIZE (2);
11178                         switch (ip [1]) {
11179                         case CEE_MONO_ICALL: {
11180                                 gpointer func;
11181                                 MonoJitICallInfo *info;
11182
11183                                 token = read32 (ip + 2);
11184                                 func = mono_method_get_wrapper_data (method, token);
11185                                 info = mono_find_jit_icall_by_addr (func);
11186                                 if (!info)
11187                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11188                                 g_assert (info);
11189
11190                                 CHECK_STACK (info->sig->param_count);
11191                                 sp -= info->sig->param_count;
11192
11193                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11194                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11195                                         *sp++ = ins;
11196
11197                                 ip += 6;
11198                                 inline_costs += 10 * num_calls++;
11199
11200                                 break;
11201                         }
11202                         case CEE_MONO_LDPTR: {
11203                                 gpointer ptr;
11204
11205                                 CHECK_STACK_OVF (1);
11206                                 CHECK_OPSIZE (6);
11207                                 token = read32 (ip + 2);
11208
11209                                 ptr = mono_method_get_wrapper_data (method, token);
11210                                 /* FIXME: Generalize this */
11211                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11212                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11213                                         *sp++ = ins;
11214                                         ip += 6;
11215                                         break;
11216                                 }
11217                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11218                                 *sp++ = ins;
11219                                 ip += 6;
11220                                 inline_costs += 10 * num_calls++;
11221                                 /* Can't embed random pointers into AOT code */
11222                                 DISABLE_AOT (cfg);
11223                                 break;
11224                         }
11225                         case CEE_MONO_JIT_ICALL_ADDR: {
11226                                 MonoJitICallInfo *callinfo;
11227                                 gpointer ptr;
11228
11229                                 CHECK_STACK_OVF (1);
11230                                 CHECK_OPSIZE (6);
11231                                 token = read32 (ip + 2);
11232
11233                                 ptr = mono_method_get_wrapper_data (method, token);
11234                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11235                                 g_assert (callinfo);
11236                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11237                                 *sp++ = ins;
11238                                 ip += 6;
11239                                 inline_costs += 10 * num_calls++;
11240                                 break;
11241                         }
11242                         case CEE_MONO_ICALL_ADDR: {
11243                                 MonoMethod *cmethod;
11244                                 gpointer ptr;
11245
11246                                 CHECK_STACK_OVF (1);
11247                                 CHECK_OPSIZE (6);
11248                                 token = read32 (ip + 2);
11249
11250                                 cmethod = mono_method_get_wrapper_data (method, token);
11251
11252                                 if (cfg->compile_aot) {
11253                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11254                                 } else {
11255                                         ptr = mono_lookup_internal_call (cmethod);
11256                                         g_assert (ptr);
11257                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11258                                 }
11259                                 *sp++ = ins;
11260                                 ip += 6;
11261                                 break;
11262                         }
11263                         case CEE_MONO_VTADDR: {
11264                                 MonoInst *src_var, *src;
11265
11266                                 CHECK_STACK (1);
11267                                 --sp;
11268
11269                                 // FIXME:
11270                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11271                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11272                                 *sp++ = src;
11273                                 ip += 2;
11274                                 break;
11275                         }
11276                         case CEE_MONO_NEWOBJ: {
11277                                 MonoInst *iargs [2];
11278
11279                                 CHECK_STACK_OVF (1);
11280                                 CHECK_OPSIZE (6);
11281                                 token = read32 (ip + 2);
11282                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11283                                 mono_class_init (klass);
11284                                 NEW_DOMAINCONST (cfg, iargs [0]);
11285                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11286                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11287                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11288                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11289                                 ip += 6;
11290                                 inline_costs += 10 * num_calls++;
11291                                 break;
11292                         }
11293                         case CEE_MONO_OBJADDR:
11294                                 CHECK_STACK (1);
11295                                 --sp;
11296                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11297                                 ins->dreg = alloc_ireg_mp (cfg);
11298                                 ins->sreg1 = sp [0]->dreg;
11299                                 ins->type = STACK_MP;
11300                                 MONO_ADD_INS (cfg->cbb, ins);
11301                                 *sp++ = ins;
11302                                 ip += 2;
11303                                 break;
11304                         case CEE_MONO_LDNATIVEOBJ:
11305                                 /*
11306                                  * Similar to LDOBJ, but instead load the unmanaged 
11307                                  * representation of the vtype to the stack.
11308                                  */
11309                                 CHECK_STACK (1);
11310                                 CHECK_OPSIZE (6);
11311                                 --sp;
11312                                 token = read32 (ip + 2);
11313                                 klass = mono_method_get_wrapper_data (method, token);
11314                                 g_assert (klass->valuetype);
11315                                 mono_class_init (klass);
11316
11317                                 {
11318                                         MonoInst *src, *dest, *temp;
11319
11320                                         src = sp [0];
11321                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11322                                         temp->backend.is_pinvoke = 1;
11323                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11324                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11325
11326                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11327                                         dest->type = STACK_VTYPE;
11328                                         dest->klass = klass;
11329
11330                                         *sp ++ = dest;
11331                                         ip += 6;
11332                                 }
11333                                 break;
11334                         case CEE_MONO_RETOBJ: {
11335                                 /*
11336                                  * Same as RET, but return the native representation of a vtype
11337                                  * to the caller.
11338                                  */
11339                                 g_assert (cfg->ret);
11340                                 g_assert (mono_method_signature (method)->pinvoke); 
11341                                 CHECK_STACK (1);
11342                                 --sp;
11343                                 
11344                                 CHECK_OPSIZE (6);
11345                                 token = read32 (ip + 2);    
11346                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11347
11348                                 if (!cfg->vret_addr) {
11349                                         g_assert (cfg->ret_var_is_local);
11350
11351                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11352                                 } else {
11353                                         EMIT_NEW_RETLOADA (cfg, ins);
11354                                 }
11355                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11356                                 
11357                                 if (sp != stack_start)
11358                                         UNVERIFIED;
11359                                 
11360                                 MONO_INST_NEW (cfg, ins, OP_BR);
11361                                 ins->inst_target_bb = end_bblock;
11362                                 MONO_ADD_INS (bblock, ins);
11363                                 link_bblock (cfg, bblock, end_bblock);
11364                                 start_new_bblock = 1;
11365                                 ip += 6;
11366                                 break;
11367                         }
11368                         case CEE_MONO_CISINST:
11369                         case CEE_MONO_CCASTCLASS: {
11370                                 int token;
11371                                 CHECK_STACK (1);
11372                                 --sp;
11373                                 CHECK_OPSIZE (6);
11374                                 token = read32 (ip + 2);
11375                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11376                                 if (ip [1] == CEE_MONO_CISINST)
11377                                         ins = handle_cisinst (cfg, klass, sp [0]);
11378                                 else
11379                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11380                                 bblock = cfg->cbb;
11381                                 *sp++ = ins;
11382                                 ip += 6;
11383                                 break;
11384                         }
11385                         case CEE_MONO_SAVE_LMF:
11386                         case CEE_MONO_RESTORE_LMF:
11387 #ifdef MONO_ARCH_HAVE_LMF_OPS
11388                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11389                                 MONO_ADD_INS (bblock, ins);
11390                                 cfg->need_lmf_area = TRUE;
11391 #endif
11392                                 ip += 2;
11393                                 break;
11394                         case CEE_MONO_CLASSCONST:
11395                                 CHECK_STACK_OVF (1);
11396                                 CHECK_OPSIZE (6);
11397                                 token = read32 (ip + 2);
11398                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11399                                 *sp++ = ins;
11400                                 ip += 6;
11401                                 inline_costs += 10 * num_calls++;
11402                                 break;
11403                         case CEE_MONO_NOT_TAKEN:
11404                                 bblock->out_of_line = TRUE;
11405                                 ip += 2;
11406                                 break;
11407                         case CEE_MONO_TLS: {
11408                                 int key;
11409
11410                                 CHECK_STACK_OVF (1);
11411                                 CHECK_OPSIZE (6);
11412                                 key = (gint32)read32 (ip + 2);
11413                                 g_assert (key < TLS_KEY_NUM);
11414
11415                                 ins = mono_create_tls_get (cfg, key);
11416                                 if (!ins) {
11417                                         if (cfg->compile_aot) {
11418                                                 DISABLE_AOT (cfg);
11419                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11420                                                 ins->dreg = alloc_preg (cfg);
11421                                                 ins->type = STACK_PTR;
11422                                         } else {
11423                                                 g_assert_not_reached ();
11424                                         }
11425                                 }
11426                                 ins->type = STACK_PTR;
11427                                 MONO_ADD_INS (bblock, ins);
11428                                 *sp++ = ins;
11429                                 ip += 6;
11430                                 break;
11431                         }
11432                         case CEE_MONO_DYN_CALL: {
11433                                 MonoCallInst *call;
11434
11435                                 /* It would be easier to call a trampoline, but that would put an
11436                                  * extra frame on the stack, confusing exception handling. So
11437                                  * implement it inline using an opcode for now.
11438                                  */
11439
11440                                 if (!cfg->dyn_call_var) {
11441                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11442                                         /* prevent it from being register allocated */
11443                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11444                                 }
11445
11446                                 /* Has to use a call inst since it local regalloc expects it */
11447                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11448                                 ins = (MonoInst*)call;
11449                                 sp -= 2;
11450                                 ins->sreg1 = sp [0]->dreg;
11451                                 ins->sreg2 = sp [1]->dreg;
11452                                 MONO_ADD_INS (bblock, ins);
11453
11454                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11455
11456                                 ip += 2;
11457                                 inline_costs += 10 * num_calls++;
11458
11459                                 break;
11460                         }
11461                         case CEE_MONO_MEMORY_BARRIER: {
11462                                 CHECK_OPSIZE (5);
11463                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11464                                 ip += 5;
11465                                 break;
11466                         }
11467                         case CEE_MONO_JIT_ATTACH: {
11468                                 MonoInst *args [16];
11469                                 MonoInst *ad_ins, *lmf_ins;
11470                                 MonoBasicBlock *next_bb = NULL;
11471
11472                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11473
11474                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11475                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11476
11477 #if TARGET_WIN32
11478                                 ad_ins = NULL;
11479                                 lmf_ins = NULL;
11480 #else
11481                                 ad_ins = mono_get_domain_intrinsic (cfg);
11482                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11483 #endif
11484
11485                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11486                                         NEW_BBLOCK (cfg, next_bb);
11487
11488                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11489                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11490                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11491
11492                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11493                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11494                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11495                                 }
11496
11497                                 if (cfg->compile_aot) {
11498                                         /* AOT code is only used in the root domain */
11499                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11500                                 } else {
11501                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11502                                 }
11503                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11504                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11505
11506                                 if (next_bb) {
11507                                         MONO_START_BB (cfg, next_bb);
11508                                         bblock = cfg->cbb;
11509                                 }
11510                                 ip += 2;
11511                                 break;
11512                         }
11513                         case CEE_MONO_JIT_DETACH: {
11514                                 MonoInst *args [16];
11515
11516                                 /* Restore the original domain */
11517                                 dreg = alloc_ireg (cfg);
11518                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11519                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11520                                 ip += 2;
11521                                 break;
11522                         }
11523                         default:
11524                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11525                                 break;
11526                         }
11527                         break;
11528                 }
11529
11530                 case CEE_PREFIX1: {
11531                         CHECK_OPSIZE (2);
11532                         switch (ip [1]) {
11533                         case CEE_ARGLIST: {
11534                                 /* somewhat similar to LDTOKEN */
11535                                 MonoInst *addr, *vtvar;
11536                                 CHECK_STACK_OVF (1);
11537                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11538
11539                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11540                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11541
11542                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11543                                 ins->type = STACK_VTYPE;
11544                                 ins->klass = mono_defaults.argumenthandle_class;
11545                                 *sp++ = ins;
11546                                 ip += 2;
11547                                 break;
11548                         }
11549                         case CEE_CEQ:
11550                         case CEE_CGT:
11551                         case CEE_CGT_UN:
11552                         case CEE_CLT:
11553                         case CEE_CLT_UN: {
11554                                 MonoInst *cmp;
11555                                 CHECK_STACK (2);
11556                                 /*
11557                                  * The following transforms:
11558                                  *    CEE_CEQ    into OP_CEQ
11559                                  *    CEE_CGT    into OP_CGT
11560                                  *    CEE_CGT_UN into OP_CGT_UN
11561                                  *    CEE_CLT    into OP_CLT
11562                                  *    CEE_CLT_UN into OP_CLT_UN
11563                                  */
11564                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11565                                 
11566                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11567                                 sp -= 2;
11568                                 cmp->sreg1 = sp [0]->dreg;
11569                                 cmp->sreg2 = sp [1]->dreg;
11570                                 type_from_op (cmp, sp [0], sp [1]);
11571                                 CHECK_TYPE (cmp);
11572                                 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))))
11573                                         cmp->opcode = OP_LCOMPARE;
11574                                 else if (sp [0]->type == STACK_R8)
11575                                         cmp->opcode = OP_FCOMPARE;
11576                                 else
11577                                         cmp->opcode = OP_ICOMPARE;
11578                                 MONO_ADD_INS (bblock, cmp);
11579                                 ins->type = STACK_I4;
11580                                 ins->dreg = alloc_dreg (cfg, ins->type);
11581                                 type_from_op (ins, sp [0], sp [1]);
11582
11583                                 if (cmp->opcode == OP_FCOMPARE) {
11584                                         /*
11585                                          * The backends expect the fceq opcodes to do the
11586                                          * comparison too.
11587                                          */
11588                                         cmp->opcode = OP_NOP;
11589                                         ins->sreg1 = cmp->sreg1;
11590                                         ins->sreg2 = cmp->sreg2;
11591                                 }
11592                                 MONO_ADD_INS (bblock, ins);
11593                                 *sp++ = ins;
11594                                 ip += 2;
11595                                 break;
11596                         }
11597                         case CEE_LDFTN: {
11598                                 MonoInst *argconst;
11599                                 MonoMethod *cil_method;
11600
11601                                 CHECK_STACK_OVF (1);
11602                                 CHECK_OPSIZE (6);
11603                                 n = read32 (ip + 2);
11604                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11605                                 if (!cmethod || mono_loader_get_last_error ())
11606                                         LOAD_ERROR;
11607                                 mono_class_init (cmethod->klass);
11608
11609                                 mono_save_token_info (cfg, image, n, cmethod);
11610
11611                                 context_used = mini_method_check_context_used (cfg, cmethod);
11612
11613                                 cil_method = cmethod;
11614                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11615                                         METHOD_ACCESS_FAILURE;
11616
11617                                 if (mono_security_cas_enabled ()) {
11618                                         if (check_linkdemand (cfg, method, cmethod))
11619                                                 INLINE_FAILURE ("linkdemand");
11620                                         CHECK_CFG_EXCEPTION;
11621                                 } else if (mono_security_core_clr_enabled ()) {
11622                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11623                                 }
11624
11625                                 /* 
11626                                  * Optimize the common case of ldftn+delegate creation
11627                                  */
11628                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11629                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11630                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11631                                                 MonoInst *target_ins;
11632                                                 MonoMethod *invoke;
11633                                                 int invoke_context_used;
11634
11635                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11636                                                 if (!invoke || !mono_method_signature (invoke))
11637                                                         LOAD_ERROR;
11638
11639                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11640
11641                                                 target_ins = sp [-1];
11642
11643                                                 if (mono_security_core_clr_enabled ())
11644                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11645
11646                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11647                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11648                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11649                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11650                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11651                                                         }
11652                                                 }
11653
11654 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11655                                                 /* FIXME: SGEN support */
11656                                                 if (invoke_context_used == 0) {
11657                                                         ip += 6;
11658                                                         if (cfg->verbose_level > 3)
11659                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11660                                                         sp --;
11661                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11662                                                         CHECK_CFG_EXCEPTION;
11663                                                         ip += 5;                        
11664                                                         sp ++;
11665                                                         break;
11666                                                 }
11667 #endif
11668                                         }
11669                                 }
11670
11671                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11672                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11673                                 *sp++ = ins;
11674                                 
11675                                 ip += 6;
11676                                 inline_costs += 10 * num_calls++;
11677                                 break;
11678                         }
11679                         case CEE_LDVIRTFTN: {
11680                                 MonoInst *args [2];
11681
11682                                 CHECK_STACK (1);
11683                                 CHECK_OPSIZE (6);
11684                                 n = read32 (ip + 2);
11685                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11686                                 if (!cmethod || mono_loader_get_last_error ())
11687                                         LOAD_ERROR;
11688                                 mono_class_init (cmethod->klass);
11689  
11690                                 context_used = mini_method_check_context_used (cfg, cmethod);
11691
11692                                 if (mono_security_cas_enabled ()) {
11693                                         if (check_linkdemand (cfg, method, cmethod))
11694                                                 INLINE_FAILURE ("linkdemand");
11695                                         CHECK_CFG_EXCEPTION;
11696                                 } else if (mono_security_core_clr_enabled ()) {
11697                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11698                                 }
11699
11700                                 --sp;
11701                                 args [0] = *sp;
11702
11703                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11704                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11705
11706                                 if (context_used)
11707                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11708                                 else
11709                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11710
11711                                 ip += 6;
11712                                 inline_costs += 10 * num_calls++;
11713                                 break;
11714                         }
11715                         case CEE_LDARG:
11716                                 CHECK_STACK_OVF (1);
11717                                 CHECK_OPSIZE (4);
11718                                 n = read16 (ip + 2);
11719                                 CHECK_ARG (n);
11720                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11721                                 *sp++ = ins;
11722                                 ip += 4;
11723                                 break;
11724                         case CEE_LDARGA:
11725                                 CHECK_STACK_OVF (1);
11726                                 CHECK_OPSIZE (4);
11727                                 n = read16 (ip + 2);
11728                                 CHECK_ARG (n);
11729                                 NEW_ARGLOADA (cfg, ins, n);
11730                                 MONO_ADD_INS (cfg->cbb, ins);
11731                                 *sp++ = ins;
11732                                 ip += 4;
11733                                 break;
11734                         case CEE_STARG:
11735                                 CHECK_STACK (1);
11736                                 --sp;
11737                                 CHECK_OPSIZE (4);
11738                                 n = read16 (ip + 2);
11739                                 CHECK_ARG (n);
11740                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11741                                         UNVERIFIED;
11742                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11743                                 ip += 4;
11744                                 break;
11745                         case CEE_LDLOC:
11746                                 CHECK_STACK_OVF (1);
11747                                 CHECK_OPSIZE (4);
11748                                 n = read16 (ip + 2);
11749                                 CHECK_LOCAL (n);
11750                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11751                                 *sp++ = ins;
11752                                 ip += 4;
11753                                 break;
11754                         case CEE_LDLOCA: {
11755                                 unsigned char *tmp_ip;
11756                                 CHECK_STACK_OVF (1);
11757                                 CHECK_OPSIZE (4);
11758                                 n = read16 (ip + 2);
11759                                 CHECK_LOCAL (n);
11760
11761                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11762                                         ip = tmp_ip;
11763                                         inline_costs += 1;
11764                                         break;
11765                                 }                       
11766                                 
11767                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11768                                 *sp++ = ins;
11769                                 ip += 4;
11770                                 break;
11771                         }
11772                         case CEE_STLOC:
11773                                 CHECK_STACK (1);
11774                                 --sp;
11775                                 CHECK_OPSIZE (4);
11776                                 n = read16 (ip + 2);
11777                                 CHECK_LOCAL (n);
11778                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11779                                         UNVERIFIED;
11780                                 emit_stloc_ir (cfg, sp, header, n);
11781                                 ip += 4;
11782                                 inline_costs += 1;
11783                                 break;
11784                         case CEE_LOCALLOC:
11785                                 CHECK_STACK (1);
11786                                 --sp;
11787                                 if (sp != stack_start) 
11788                                         UNVERIFIED;
11789                                 if (cfg->method != method) 
11790                                         /* 
11791                                          * Inlining this into a loop in a parent could lead to 
11792                                          * stack overflows which is different behavior than the
11793                                          * non-inlined case, thus disable inlining in this case.
11794                                          */
11795                                         goto inline_failure;
11796
11797                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11798                                 ins->dreg = alloc_preg (cfg);
11799                                 ins->sreg1 = sp [0]->dreg;
11800                                 ins->type = STACK_PTR;
11801                                 MONO_ADD_INS (cfg->cbb, ins);
11802
11803                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11804                                 if (init_locals)
11805                                         ins->flags |= MONO_INST_INIT;
11806
11807                                 *sp++ = ins;
11808                                 ip += 2;
11809                                 break;
11810                         case CEE_ENDFILTER: {
11811                                 MonoExceptionClause *clause, *nearest;
11812                                 int cc, nearest_num;
11813
11814                                 CHECK_STACK (1);
11815                                 --sp;
11816                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11817                                         UNVERIFIED;
11818                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11819                                 ins->sreg1 = (*sp)->dreg;
11820                                 MONO_ADD_INS (bblock, ins);
11821                                 start_new_bblock = 1;
11822                                 ip += 2;
11823
11824                                 nearest = NULL;
11825                                 nearest_num = 0;
11826                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11827                                         clause = &header->clauses [cc];
11828                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11829                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11830                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11831                                                 nearest = clause;
11832                                                 nearest_num = cc;
11833                                         }
11834                                 }
11835                                 g_assert (nearest);
11836                                 if ((ip - header->code) != nearest->handler_offset)
11837                                         UNVERIFIED;
11838
11839                                 break;
11840                         }
11841                         case CEE_UNALIGNED_:
11842                                 ins_flag |= MONO_INST_UNALIGNED;
11843                                 /* FIXME: record alignment? we can assume 1 for now */
11844                                 CHECK_OPSIZE (3);
11845                                 ip += 3;
11846                                 break;
11847                         case CEE_VOLATILE_:
11848                                 ins_flag |= MONO_INST_VOLATILE;
11849                                 ip += 2;
11850                                 break;
11851                         case CEE_TAIL_:
11852                                 ins_flag   |= MONO_INST_TAILCALL;
11853                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11854                                 /* Can't inline tail calls at this time */
11855                                 inline_costs += 100000;
11856                                 ip += 2;
11857                                 break;
11858                         case CEE_INITOBJ:
11859                                 CHECK_STACK (1);
11860                                 --sp;
11861                                 CHECK_OPSIZE (6);
11862                                 token = read32 (ip + 2);
11863                                 klass = mini_get_class (method, token, generic_context);
11864                                 CHECK_TYPELOAD (klass);
11865                                 if (generic_class_is_reference_type (cfg, klass))
11866                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11867                                 else
11868                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11869                                 ip += 6;
11870                                 inline_costs += 1;
11871                                 break;
11872                         case CEE_CONSTRAINED_:
11873                                 CHECK_OPSIZE (6);
11874                                 token = read32 (ip + 2);
11875                                 constrained_call = mini_get_class (method, token, generic_context);
11876                                 CHECK_TYPELOAD (constrained_call);
11877                                 ip += 6;
11878                                 break;
11879                         case CEE_CPBLK:
11880                         case CEE_INITBLK: {
11881                                 MonoInst *iargs [3];
11882                                 CHECK_STACK (3);
11883                                 sp -= 3;
11884
11885                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11886                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11887                                 } 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)) {
11888                                         /* emit_memset only works when val == 0 */
11889                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11890                                 } else {
11891                                         iargs [0] = sp [0];
11892                                         iargs [1] = sp [1];
11893                                         iargs [2] = sp [2];
11894                                         if (ip [1] == CEE_CPBLK) {
11895                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11896                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11897                                         } else {
11898                                                 MonoMethod *memset_method = get_memset_method ();
11899                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11900                                         }
11901                                 }
11902                                 ip += 2;
11903                                 inline_costs += 1;
11904                                 break;
11905                         }
11906                         case CEE_NO_:
11907                                 CHECK_OPSIZE (3);
11908                                 if (ip [2] & 0x1)
11909                                         ins_flag |= MONO_INST_NOTYPECHECK;
11910                                 if (ip [2] & 0x2)
11911                                         ins_flag |= MONO_INST_NORANGECHECK;
11912                                 /* we ignore the no-nullcheck for now since we
11913                                  * really do it explicitly only when doing callvirt->call
11914                                  */
11915                                 ip += 3;
11916                                 break;
11917                         case CEE_RETHROW: {
11918                                 MonoInst *load;
11919                                 int handler_offset = -1;
11920
11921                                 for (i = 0; i < header->num_clauses; ++i) {
11922                                         MonoExceptionClause *clause = &header->clauses [i];
11923                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11924                                                 handler_offset = clause->handler_offset;
11925                                                 break;
11926                                         }
11927                                 }
11928
11929                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11930
11931                                 g_assert (handler_offset != -1);
11932
11933                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11934                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11935                                 ins->sreg1 = load->dreg;
11936                                 MONO_ADD_INS (bblock, ins);
11937
11938                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11939                                 MONO_ADD_INS (bblock, ins);
11940
11941                                 sp = stack_start;
11942                                 link_bblock (cfg, bblock, end_bblock);
11943                                 start_new_bblock = 1;
11944                                 ip += 2;
11945                                 break;
11946                         }
11947                         case CEE_SIZEOF: {
11948                                 guint32 val;
11949                                 int ialign;
11950
11951                                 GSHAREDVT_FAILURE (*ip);
11952
11953                                 CHECK_STACK_OVF (1);
11954                                 CHECK_OPSIZE (6);
11955                                 token = read32 (ip + 2);
11956                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11957                                         MonoType *type = mono_type_create_from_typespec (image, token);
11958                                         val = mono_type_size (type, &ialign);
11959                                 } else {
11960                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11961                                         CHECK_TYPELOAD (klass);
11962                                         mono_class_init (klass);
11963                                         val = mono_type_size (&klass->byval_arg, &ialign);
11964                                 }
11965                                 EMIT_NEW_ICONST (cfg, ins, val);
11966                                 *sp++= ins;
11967                                 ip += 6;
11968                                 break;
11969                         }
11970                         case CEE_REFANYTYPE: {
11971                                 MonoInst *src_var, *src;
11972
11973                                 GSHAREDVT_FAILURE (*ip);
11974
11975                                 CHECK_STACK (1);
11976                                 --sp;
11977
11978                                 // FIXME:
11979                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11980                                 if (!src_var)
11981                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11982                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11983                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
11984                                 *sp++ = ins;
11985                                 ip += 2;
11986                                 break;
11987                         }
11988                         case CEE_READONLY_:
11989                                 readonly = TRUE;
11990                                 ip += 2;
11991                                 break;
11992
11993                         case CEE_UNUSED56:
11994                         case CEE_UNUSED57:
11995                         case CEE_UNUSED70:
11996                         case CEE_UNUSED:
11997                         case CEE_UNUSED99:
11998                                 UNVERIFIED;
11999                                 
12000                         default:
12001                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12002                                 UNVERIFIED;
12003                         }
12004                         break;
12005                 }
12006                 case CEE_UNUSED58:
12007                 case CEE_UNUSED1:
12008                         UNVERIFIED;
12009
12010                 default:
12011                         g_warning ("opcode 0x%02x not handled", *ip);
12012                         UNVERIFIED;
12013                 }
12014         }
12015         if (start_new_bblock != 1)
12016                 UNVERIFIED;
12017
12018         bblock->cil_length = ip - bblock->cil_code;
12019         if (bblock->next_bb) {
12020                 /* This could already be set because of inlining, #693905 */
12021                 MonoBasicBlock *bb = bblock;
12022
12023                 while (bb->next_bb)
12024                         bb = bb->next_bb;
12025                 bb->next_bb = end_bblock;
12026         } else {
12027                 bblock->next_bb = end_bblock;
12028         }
12029
12030         if (cfg->method == method && cfg->domainvar) {
12031                 MonoInst *store;
12032                 MonoInst *get_domain;
12033
12034                 cfg->cbb = init_localsbb;
12035
12036                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12037                         MONO_ADD_INS (cfg->cbb, get_domain);
12038                 } else {
12039                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12040                 }
12041                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12042                 MONO_ADD_INS (cfg->cbb, store);
12043         }
12044
12045 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12046         if (cfg->compile_aot)
12047                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12048                 mono_get_got_var (cfg);
12049 #endif
12050
12051         if (cfg->method == method && cfg->got_var)
12052                 mono_emit_load_got_addr (cfg);
12053
12054         if (init_localsbb) {
12055                 cfg->cbb = init_localsbb;
12056                 cfg->ip = NULL;
12057                 for (i = 0; i < header->num_locals; ++i) {
12058                         emit_init_local (cfg, i, header->locals [i], init_locals);
12059                 }
12060         }
12061
12062         if (cfg->init_ref_vars && cfg->method == method) {
12063                 /* Emit initialization for ref vars */
12064                 // FIXME: Avoid duplication initialization for IL locals.
12065                 for (i = 0; i < cfg->num_varinfo; ++i) {
12066                         MonoInst *ins = cfg->varinfo [i];
12067
12068                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12069                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12070                 }
12071         }
12072
12073         if (cfg->lmf_var && cfg->method == method) {
12074                 cfg->cbb = init_localsbb;
12075                 emit_push_lmf (cfg);
12076         }
12077
12078         if (seq_points) {
12079                 MonoBasicBlock *bb;
12080
12081                 /*
12082                  * Make seq points at backward branch targets interruptable.
12083                  */
12084                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12085                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12086                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12087         }
12088
12089         /* Add a sequence point for method entry/exit events */
12090         if (seq_points) {
12091                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12092                 MONO_ADD_INS (init_localsbb, ins);
12093                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12094                 MONO_ADD_INS (cfg->bb_exit, ins);
12095         }
12096
12097         /*
12098          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12099          * the code they refer to was dead (#11880).
12100          */
12101         if (sym_seq_points) {
12102                 for (i = 0; i < header->code_size; ++i) {
12103                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12104                                 MonoInst *ins;
12105
12106                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12107                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12108                         }
12109                 }
12110         }
12111
12112         cfg->ip = NULL;
12113
12114         if (cfg->method == method) {
12115                 MonoBasicBlock *bb;
12116                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12117                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12118                         if (cfg->spvars)
12119                                 mono_create_spvar_for_region (cfg, bb->region);
12120                         if (cfg->verbose_level > 2)
12121                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12122                 }
12123         }
12124
12125         g_slist_free (class_inits);
12126         dont_inline = g_list_remove (dont_inline, method);
12127
12128         if (inline_costs < 0) {
12129                 char *mname;
12130
12131                 /* Method is too large */
12132                 mname = mono_method_full_name (method, TRUE);
12133                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12134                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12135                 g_free (mname);
12136                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12137                 mono_basic_block_free (original_bb);
12138                 return -1;
12139         }
12140
12141         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12142                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12143
12144         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12145         mono_basic_block_free (original_bb);
12146         return inline_costs;
12147  
12148  exception_exit:
12149         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12150         goto cleanup;
12151
12152  inline_failure:
12153         goto cleanup;
12154
12155  load_error:
12156         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
12157         goto cleanup;
12158
12159  unverified:
12160         set_exception_type_from_invalid_il (cfg, method, ip);
12161         goto cleanup;
12162
12163  cleanup:
12164         g_slist_free (class_inits);
12165         mono_basic_block_free (original_bb);
12166         dont_inline = g_list_remove (dont_inline, method);
12167         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12168         return -1;
12169 }
12170
12171 static int
12172 store_membase_reg_to_store_membase_imm (int opcode)
12173 {
12174         switch (opcode) {
12175         case OP_STORE_MEMBASE_REG:
12176                 return OP_STORE_MEMBASE_IMM;
12177         case OP_STOREI1_MEMBASE_REG:
12178                 return OP_STOREI1_MEMBASE_IMM;
12179         case OP_STOREI2_MEMBASE_REG:
12180                 return OP_STOREI2_MEMBASE_IMM;
12181         case OP_STOREI4_MEMBASE_REG:
12182                 return OP_STOREI4_MEMBASE_IMM;
12183         case OP_STOREI8_MEMBASE_REG:
12184                 return OP_STOREI8_MEMBASE_IMM;
12185         default:
12186                 g_assert_not_reached ();
12187         }
12188
12189         return -1;
12190 }               
12191
12192 int
12193 mono_op_to_op_imm (int opcode)
12194 {
12195         switch (opcode) {
12196         case OP_IADD:
12197                 return OP_IADD_IMM;
12198         case OP_ISUB:
12199                 return OP_ISUB_IMM;
12200         case OP_IDIV:
12201                 return OP_IDIV_IMM;
12202         case OP_IDIV_UN:
12203                 return OP_IDIV_UN_IMM;
12204         case OP_IREM:
12205                 return OP_IREM_IMM;
12206         case OP_IREM_UN:
12207                 return OP_IREM_UN_IMM;
12208         case OP_IMUL:
12209                 return OP_IMUL_IMM;
12210         case OP_IAND:
12211                 return OP_IAND_IMM;
12212         case OP_IOR:
12213                 return OP_IOR_IMM;
12214         case OP_IXOR:
12215                 return OP_IXOR_IMM;
12216         case OP_ISHL:
12217                 return OP_ISHL_IMM;
12218         case OP_ISHR:
12219                 return OP_ISHR_IMM;
12220         case OP_ISHR_UN:
12221                 return OP_ISHR_UN_IMM;
12222
12223         case OP_LADD:
12224                 return OP_LADD_IMM;
12225         case OP_LSUB:
12226                 return OP_LSUB_IMM;
12227         case OP_LAND:
12228                 return OP_LAND_IMM;
12229         case OP_LOR:
12230                 return OP_LOR_IMM;
12231         case OP_LXOR:
12232                 return OP_LXOR_IMM;
12233         case OP_LSHL:
12234                 return OP_LSHL_IMM;
12235         case OP_LSHR:
12236                 return OP_LSHR_IMM;
12237         case OP_LSHR_UN:
12238                 return OP_LSHR_UN_IMM;          
12239
12240         case OP_COMPARE:
12241                 return OP_COMPARE_IMM;
12242         case OP_ICOMPARE:
12243                 return OP_ICOMPARE_IMM;
12244         case OP_LCOMPARE:
12245                 return OP_LCOMPARE_IMM;
12246
12247         case OP_STORE_MEMBASE_REG:
12248                 return OP_STORE_MEMBASE_IMM;
12249         case OP_STOREI1_MEMBASE_REG:
12250                 return OP_STOREI1_MEMBASE_IMM;
12251         case OP_STOREI2_MEMBASE_REG:
12252                 return OP_STOREI2_MEMBASE_IMM;
12253         case OP_STOREI4_MEMBASE_REG:
12254                 return OP_STOREI4_MEMBASE_IMM;
12255
12256 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12257         case OP_X86_PUSH:
12258                 return OP_X86_PUSH_IMM;
12259         case OP_X86_COMPARE_MEMBASE_REG:
12260                 return OP_X86_COMPARE_MEMBASE_IMM;
12261 #endif
12262 #if defined(TARGET_AMD64)
12263         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12264                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12265 #endif
12266         case OP_VOIDCALL_REG:
12267                 return OP_VOIDCALL;
12268         case OP_CALL_REG:
12269                 return OP_CALL;
12270         case OP_LCALL_REG:
12271                 return OP_LCALL;
12272         case OP_FCALL_REG:
12273                 return OP_FCALL;
12274         case OP_LOCALLOC:
12275                 return OP_LOCALLOC_IMM;
12276         }
12277
12278         return -1;
12279 }
12280
12281 static int
12282 ldind_to_load_membase (int opcode)
12283 {
12284         switch (opcode) {
12285         case CEE_LDIND_I1:
12286                 return OP_LOADI1_MEMBASE;
12287         case CEE_LDIND_U1:
12288                 return OP_LOADU1_MEMBASE;
12289         case CEE_LDIND_I2:
12290                 return OP_LOADI2_MEMBASE;
12291         case CEE_LDIND_U2:
12292                 return OP_LOADU2_MEMBASE;
12293         case CEE_LDIND_I4:
12294                 return OP_LOADI4_MEMBASE;
12295         case CEE_LDIND_U4:
12296                 return OP_LOADU4_MEMBASE;
12297         case CEE_LDIND_I:
12298                 return OP_LOAD_MEMBASE;
12299         case CEE_LDIND_REF:
12300                 return OP_LOAD_MEMBASE;
12301         case CEE_LDIND_I8:
12302                 return OP_LOADI8_MEMBASE;
12303         case CEE_LDIND_R4:
12304                 return OP_LOADR4_MEMBASE;
12305         case CEE_LDIND_R8:
12306                 return OP_LOADR8_MEMBASE;
12307         default:
12308                 g_assert_not_reached ();
12309         }
12310
12311         return -1;
12312 }
12313
12314 static int
12315 stind_to_store_membase (int opcode)
12316 {
12317         switch (opcode) {
12318         case CEE_STIND_I1:
12319                 return OP_STOREI1_MEMBASE_REG;
12320         case CEE_STIND_I2:
12321                 return OP_STOREI2_MEMBASE_REG;
12322         case CEE_STIND_I4:
12323                 return OP_STOREI4_MEMBASE_REG;
12324         case CEE_STIND_I:
12325         case CEE_STIND_REF:
12326                 return OP_STORE_MEMBASE_REG;
12327         case CEE_STIND_I8:
12328                 return OP_STOREI8_MEMBASE_REG;
12329         case CEE_STIND_R4:
12330                 return OP_STORER4_MEMBASE_REG;
12331         case CEE_STIND_R8:
12332                 return OP_STORER8_MEMBASE_REG;
12333         default:
12334                 g_assert_not_reached ();
12335         }
12336
12337         return -1;
12338 }
12339
12340 int
12341 mono_load_membase_to_load_mem (int opcode)
12342 {
12343         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12344 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12345         switch (opcode) {
12346         case OP_LOAD_MEMBASE:
12347                 return OP_LOAD_MEM;
12348         case OP_LOADU1_MEMBASE:
12349                 return OP_LOADU1_MEM;
12350         case OP_LOADU2_MEMBASE:
12351                 return OP_LOADU2_MEM;
12352         case OP_LOADI4_MEMBASE:
12353                 return OP_LOADI4_MEM;
12354         case OP_LOADU4_MEMBASE:
12355                 return OP_LOADU4_MEM;
12356 #if SIZEOF_REGISTER == 8
12357         case OP_LOADI8_MEMBASE:
12358                 return OP_LOADI8_MEM;
12359 #endif
12360         }
12361 #endif
12362
12363         return -1;
12364 }
12365
12366 static inline int
12367 op_to_op_dest_membase (int store_opcode, int opcode)
12368 {
12369 #if defined(TARGET_X86)
12370         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12371                 return -1;
12372
12373         switch (opcode) {
12374         case OP_IADD:
12375                 return OP_X86_ADD_MEMBASE_REG;
12376         case OP_ISUB:
12377                 return OP_X86_SUB_MEMBASE_REG;
12378         case OP_IAND:
12379                 return OP_X86_AND_MEMBASE_REG;
12380         case OP_IOR:
12381                 return OP_X86_OR_MEMBASE_REG;
12382         case OP_IXOR:
12383                 return OP_X86_XOR_MEMBASE_REG;
12384         case OP_ADD_IMM:
12385         case OP_IADD_IMM:
12386                 return OP_X86_ADD_MEMBASE_IMM;
12387         case OP_SUB_IMM:
12388         case OP_ISUB_IMM:
12389                 return OP_X86_SUB_MEMBASE_IMM;
12390         case OP_AND_IMM:
12391         case OP_IAND_IMM:
12392                 return OP_X86_AND_MEMBASE_IMM;
12393         case OP_OR_IMM:
12394         case OP_IOR_IMM:
12395                 return OP_X86_OR_MEMBASE_IMM;
12396         case OP_XOR_IMM:
12397         case OP_IXOR_IMM:
12398                 return OP_X86_XOR_MEMBASE_IMM;
12399         case OP_MOVE:
12400                 return OP_NOP;
12401         }
12402 #endif
12403
12404 #if defined(TARGET_AMD64)
12405         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12406                 return -1;
12407
12408         switch (opcode) {
12409         case OP_IADD:
12410                 return OP_X86_ADD_MEMBASE_REG;
12411         case OP_ISUB:
12412                 return OP_X86_SUB_MEMBASE_REG;
12413         case OP_IAND:
12414                 return OP_X86_AND_MEMBASE_REG;
12415         case OP_IOR:
12416                 return OP_X86_OR_MEMBASE_REG;
12417         case OP_IXOR:
12418                 return OP_X86_XOR_MEMBASE_REG;
12419         case OP_IADD_IMM:
12420                 return OP_X86_ADD_MEMBASE_IMM;
12421         case OP_ISUB_IMM:
12422                 return OP_X86_SUB_MEMBASE_IMM;
12423         case OP_IAND_IMM:
12424                 return OP_X86_AND_MEMBASE_IMM;
12425         case OP_IOR_IMM:
12426                 return OP_X86_OR_MEMBASE_IMM;
12427         case OP_IXOR_IMM:
12428                 return OP_X86_XOR_MEMBASE_IMM;
12429         case OP_LADD:
12430                 return OP_AMD64_ADD_MEMBASE_REG;
12431         case OP_LSUB:
12432                 return OP_AMD64_SUB_MEMBASE_REG;
12433         case OP_LAND:
12434                 return OP_AMD64_AND_MEMBASE_REG;
12435         case OP_LOR:
12436                 return OP_AMD64_OR_MEMBASE_REG;
12437         case OP_LXOR:
12438                 return OP_AMD64_XOR_MEMBASE_REG;
12439         case OP_ADD_IMM:
12440         case OP_LADD_IMM:
12441                 return OP_AMD64_ADD_MEMBASE_IMM;
12442         case OP_SUB_IMM:
12443         case OP_LSUB_IMM:
12444                 return OP_AMD64_SUB_MEMBASE_IMM;
12445         case OP_AND_IMM:
12446         case OP_LAND_IMM:
12447                 return OP_AMD64_AND_MEMBASE_IMM;
12448         case OP_OR_IMM:
12449         case OP_LOR_IMM:
12450                 return OP_AMD64_OR_MEMBASE_IMM;
12451         case OP_XOR_IMM:
12452         case OP_LXOR_IMM:
12453                 return OP_AMD64_XOR_MEMBASE_IMM;
12454         case OP_MOVE:
12455                 return OP_NOP;
12456         }
12457 #endif
12458
12459         return -1;
12460 }
12461
12462 static inline int
12463 op_to_op_store_membase (int store_opcode, int opcode)
12464 {
12465 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12466         switch (opcode) {
12467         case OP_ICEQ:
12468                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12469                         return OP_X86_SETEQ_MEMBASE;
12470         case OP_CNE:
12471                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12472                         return OP_X86_SETNE_MEMBASE;
12473         }
12474 #endif
12475
12476         return -1;
12477 }
12478
12479 static inline int
12480 op_to_op_src1_membase (int load_opcode, int opcode)
12481 {
12482 #ifdef TARGET_X86
12483         /* FIXME: This has sign extension issues */
12484         /*
12485         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12486                 return OP_X86_COMPARE_MEMBASE8_IMM;
12487         */
12488
12489         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12490                 return -1;
12491
12492         switch (opcode) {
12493         case OP_X86_PUSH:
12494                 return OP_X86_PUSH_MEMBASE;
12495         case OP_COMPARE_IMM:
12496         case OP_ICOMPARE_IMM:
12497                 return OP_X86_COMPARE_MEMBASE_IMM;
12498         case OP_COMPARE:
12499         case OP_ICOMPARE:
12500                 return OP_X86_COMPARE_MEMBASE_REG;
12501         }
12502 #endif
12503
12504 #ifdef TARGET_AMD64
12505         /* FIXME: This has sign extension issues */
12506         /*
12507         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12508                 return OP_X86_COMPARE_MEMBASE8_IMM;
12509         */
12510
12511         switch (opcode) {
12512         case OP_X86_PUSH:
12513 #ifdef __mono_ilp32__
12514                 if (load_opcode == OP_LOADI8_MEMBASE)
12515 #else
12516                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12517 #endif
12518                         return OP_X86_PUSH_MEMBASE;
12519                 break;
12520                 /* FIXME: This only works for 32 bit immediates
12521         case OP_COMPARE_IMM:
12522         case OP_LCOMPARE_IMM:
12523                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12524                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12525                 */
12526         case OP_ICOMPARE_IMM:
12527                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12528                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12529                 break;
12530         case OP_COMPARE:
12531         case OP_LCOMPARE:
12532 #ifdef __mono_ilp32__
12533                 if (load_opcode == OP_LOAD_MEMBASE)
12534                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12535                 if (load_opcode == OP_LOADI8_MEMBASE)
12536 #else
12537                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12538 #endif
12539                         return OP_AMD64_COMPARE_MEMBASE_REG;
12540                 break;
12541         case OP_ICOMPARE:
12542                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12543                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12544                 break;
12545         }
12546 #endif
12547
12548         return -1;
12549 }
12550
12551 static inline int
12552 op_to_op_src2_membase (int load_opcode, int opcode)
12553 {
12554 #ifdef TARGET_X86
12555         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12556                 return -1;
12557         
12558         switch (opcode) {
12559         case OP_COMPARE:
12560         case OP_ICOMPARE:
12561                 return OP_X86_COMPARE_REG_MEMBASE;
12562         case OP_IADD:
12563                 return OP_X86_ADD_REG_MEMBASE;
12564         case OP_ISUB:
12565                 return OP_X86_SUB_REG_MEMBASE;
12566         case OP_IAND:
12567                 return OP_X86_AND_REG_MEMBASE;
12568         case OP_IOR:
12569                 return OP_X86_OR_REG_MEMBASE;
12570         case OP_IXOR:
12571                 return OP_X86_XOR_REG_MEMBASE;
12572         }
12573 #endif
12574
12575 #ifdef TARGET_AMD64
12576 #ifdef __mono_ilp32__
12577         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12578 #else
12579         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12580 #endif
12581                 switch (opcode) {
12582                 case OP_ICOMPARE:
12583                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12584                 case OP_IADD:
12585                         return OP_X86_ADD_REG_MEMBASE;
12586                 case OP_ISUB:
12587                         return OP_X86_SUB_REG_MEMBASE;
12588                 case OP_IAND:
12589                         return OP_X86_AND_REG_MEMBASE;
12590                 case OP_IOR:
12591                         return OP_X86_OR_REG_MEMBASE;
12592                 case OP_IXOR:
12593                         return OP_X86_XOR_REG_MEMBASE;
12594                 }
12595 #ifdef __mono_ilp32__
12596         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12597 #else
12598         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12599 #endif
12600                 switch (opcode) {
12601                 case OP_COMPARE:
12602                 case OP_LCOMPARE:
12603                         return OP_AMD64_COMPARE_REG_MEMBASE;
12604                 case OP_LADD:
12605                         return OP_AMD64_ADD_REG_MEMBASE;
12606                 case OP_LSUB:
12607                         return OP_AMD64_SUB_REG_MEMBASE;
12608                 case OP_LAND:
12609                         return OP_AMD64_AND_REG_MEMBASE;
12610                 case OP_LOR:
12611                         return OP_AMD64_OR_REG_MEMBASE;
12612                 case OP_LXOR:
12613                         return OP_AMD64_XOR_REG_MEMBASE;
12614                 }
12615         }
12616 #endif
12617
12618         return -1;
12619 }
12620
12621 int
12622 mono_op_to_op_imm_noemul (int opcode)
12623 {
12624         switch (opcode) {
12625 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12626         case OP_LSHR:
12627         case OP_LSHL:
12628         case OP_LSHR_UN:
12629                 return -1;
12630 #endif
12631 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12632         case OP_IDIV:
12633         case OP_IDIV_UN:
12634         case OP_IREM:
12635         case OP_IREM_UN:
12636                 return -1;
12637 #endif
12638 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12639         case OP_IMUL:
12640                 return -1;
12641 #endif
12642         default:
12643                 return mono_op_to_op_imm (opcode);
12644         }
12645 }
12646
12647 /**
12648  * mono_handle_global_vregs:
12649  *
12650  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12651  * for them.
12652  */
12653 void
12654 mono_handle_global_vregs (MonoCompile *cfg)
12655 {
12656         gint32 *vreg_to_bb;
12657         MonoBasicBlock *bb;
12658         int i, pos;
12659
12660         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12661
12662 #ifdef MONO_ARCH_SIMD_INTRINSICS
12663         if (cfg->uses_simd_intrinsics)
12664                 mono_simd_simplify_indirection (cfg);
12665 #endif
12666
12667         /* Find local vregs used in more than one bb */
12668         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12669                 MonoInst *ins = bb->code;       
12670                 int block_num = bb->block_num;
12671
12672                 if (cfg->verbose_level > 2)
12673                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12674
12675                 cfg->cbb = bb;
12676                 for (; ins; ins = ins->next) {
12677                         const char *spec = INS_INFO (ins->opcode);
12678                         int regtype = 0, regindex;
12679                         gint32 prev_bb;
12680
12681                         if (G_UNLIKELY (cfg->verbose_level > 2))
12682                                 mono_print_ins (ins);
12683
12684                         g_assert (ins->opcode >= MONO_CEE_LAST);
12685
12686                         for (regindex = 0; regindex < 4; regindex ++) {
12687                                 int vreg = 0;
12688
12689                                 if (regindex == 0) {
12690                                         regtype = spec [MONO_INST_DEST];
12691                                         if (regtype == ' ')
12692                                                 continue;
12693                                         vreg = ins->dreg;
12694                                 } else if (regindex == 1) {
12695                                         regtype = spec [MONO_INST_SRC1];
12696                                         if (regtype == ' ')
12697                                                 continue;
12698                                         vreg = ins->sreg1;
12699                                 } else if (regindex == 2) {
12700                                         regtype = spec [MONO_INST_SRC2];
12701                                         if (regtype == ' ')
12702                                                 continue;
12703                                         vreg = ins->sreg2;
12704                                 } else if (regindex == 3) {
12705                                         regtype = spec [MONO_INST_SRC3];
12706                                         if (regtype == ' ')
12707                                                 continue;
12708                                         vreg = ins->sreg3;
12709                                 }
12710
12711 #if SIZEOF_REGISTER == 4
12712                                 /* In the LLVM case, the long opcodes are not decomposed */
12713                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12714                                         /*
12715                                          * Since some instructions reference the original long vreg,
12716                                          * and some reference the two component vregs, it is quite hard
12717                                          * to determine when it needs to be global. So be conservative.
12718                                          */
12719                                         if (!get_vreg_to_inst (cfg, vreg)) {
12720                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12721
12722                                                 if (cfg->verbose_level > 2)
12723                                                         printf ("LONG VREG R%d made global.\n", vreg);
12724                                         }
12725
12726                                         /*
12727                                          * Make the component vregs volatile since the optimizations can
12728                                          * get confused otherwise.
12729                                          */
12730                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12731                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12732                                 }
12733 #endif
12734
12735                                 g_assert (vreg != -1);
12736
12737                                 prev_bb = vreg_to_bb [vreg];
12738                                 if (prev_bb == 0) {
12739                                         /* 0 is a valid block num */
12740                                         vreg_to_bb [vreg] = block_num + 1;
12741                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12742                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12743                                                 continue;
12744
12745                                         if (!get_vreg_to_inst (cfg, vreg)) {
12746                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12747                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12748
12749                                                 switch (regtype) {
12750                                                 case 'i':
12751                                                         if (vreg_is_ref (cfg, vreg))
12752                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12753                                                         else
12754                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12755                                                         break;
12756                                                 case 'l':
12757                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12758                                                         break;
12759                                                 case 'f':
12760                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12761                                                         break;
12762                                                 case 'v':
12763                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12764                                                         break;
12765                                                 default:
12766                                                         g_assert_not_reached ();
12767                                                 }
12768                                         }
12769
12770                                         /* Flag as having been used in more than one bb */
12771                                         vreg_to_bb [vreg] = -1;
12772                                 }
12773                         }
12774                 }
12775         }
12776
12777         /* If a variable is used in only one bblock, convert it into a local vreg */
12778         for (i = 0; i < cfg->num_varinfo; i++) {
12779                 MonoInst *var = cfg->varinfo [i];
12780                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12781
12782                 switch (var->type) {
12783                 case STACK_I4:
12784                 case STACK_OBJ:
12785                 case STACK_PTR:
12786                 case STACK_MP:
12787                 case STACK_VTYPE:
12788 #if SIZEOF_REGISTER == 8
12789                 case STACK_I8:
12790 #endif
12791 #if !defined(TARGET_X86)
12792                 /* Enabling this screws up the fp stack on x86 */
12793                 case STACK_R8:
12794 #endif
12795                         if (mono_arch_is_soft_float ())
12796                                 break;
12797
12798                         /* Arguments are implicitly global */
12799                         /* Putting R4 vars into registers doesn't work currently */
12800                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12801                         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) {
12802                                 /* 
12803                                  * Make that the variable's liveness interval doesn't contain a call, since
12804                                  * that would cause the lvreg to be spilled, making the whole optimization
12805                                  * useless.
12806                                  */
12807                                 /* This is too slow for JIT compilation */
12808 #if 0
12809                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12810                                         MonoInst *ins;
12811                                         int def_index, call_index, ins_index;
12812                                         gboolean spilled = FALSE;
12813
12814                                         def_index = -1;
12815                                         call_index = -1;
12816                                         ins_index = 0;
12817                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12818                                                 const char *spec = INS_INFO (ins->opcode);
12819
12820                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12821                                                         def_index = ins_index;
12822
12823                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12824                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12825                                                         if (call_index > def_index) {
12826                                                                 spilled = TRUE;
12827                                                                 break;
12828                                                         }
12829                                                 }
12830
12831                                                 if (MONO_IS_CALL (ins))
12832                                                         call_index = ins_index;
12833
12834                                                 ins_index ++;
12835                                         }
12836
12837                                         if (spilled)
12838                                                 break;
12839                                 }
12840 #endif
12841
12842                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12843                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12844                                 var->flags |= MONO_INST_IS_DEAD;
12845                                 cfg->vreg_to_inst [var->dreg] = NULL;
12846                         }
12847                         break;
12848                 }
12849         }
12850
12851         /* 
12852          * Compress the varinfo and vars tables so the liveness computation is faster and
12853          * takes up less space.
12854          */
12855         pos = 0;
12856         for (i = 0; i < cfg->num_varinfo; ++i) {
12857                 MonoInst *var = cfg->varinfo [i];
12858                 if (pos < i && cfg->locals_start == i)
12859                         cfg->locals_start = pos;
12860                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12861                         if (pos < i) {
12862                                 cfg->varinfo [pos] = cfg->varinfo [i];
12863                                 cfg->varinfo [pos]->inst_c0 = pos;
12864                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12865                                 cfg->vars [pos].idx = pos;
12866 #if SIZEOF_REGISTER == 4
12867                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12868                                         /* Modify the two component vars too */
12869                                         MonoInst *var1;
12870
12871                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12872                                         var1->inst_c0 = pos;
12873                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12874                                         var1->inst_c0 = pos;
12875                                 }
12876 #endif
12877                         }
12878                         pos ++;
12879                 }
12880         }
12881         cfg->num_varinfo = pos;
12882         if (cfg->locals_start > cfg->num_varinfo)
12883                 cfg->locals_start = cfg->num_varinfo;
12884 }
12885
12886 /**
12887  * mono_spill_global_vars:
12888  *
12889  *   Generate spill code for variables which are not allocated to registers, 
12890  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12891  * code is generated which could be optimized by the local optimization passes.
12892  */
12893 void
12894 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12895 {
12896         MonoBasicBlock *bb;
12897         char spec2 [16];
12898         int orig_next_vreg;
12899         guint32 *vreg_to_lvreg;
12900         guint32 *lvregs;
12901         guint32 i, lvregs_len;
12902         gboolean dest_has_lvreg = FALSE;
12903         guint32 stacktypes [128];
12904         MonoInst **live_range_start, **live_range_end;
12905         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12906         int *gsharedvt_vreg_to_idx = NULL;
12907
12908         *need_local_opts = FALSE;
12909
12910         memset (spec2, 0, sizeof (spec2));
12911
12912         /* FIXME: Move this function to mini.c */
12913         stacktypes ['i'] = STACK_PTR;
12914         stacktypes ['l'] = STACK_I8;
12915         stacktypes ['f'] = STACK_R8;
12916 #ifdef MONO_ARCH_SIMD_INTRINSICS
12917         stacktypes ['x'] = STACK_VTYPE;
12918 #endif
12919
12920 #if SIZEOF_REGISTER == 4
12921         /* Create MonoInsts for longs */
12922         for (i = 0; i < cfg->num_varinfo; i++) {
12923                 MonoInst *ins = cfg->varinfo [i];
12924
12925                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12926                         switch (ins->type) {
12927                         case STACK_R8:
12928                         case STACK_I8: {
12929                                 MonoInst *tree;
12930
12931                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12932                                         break;
12933
12934                                 g_assert (ins->opcode == OP_REGOFFSET);
12935
12936                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12937                                 g_assert (tree);
12938                                 tree->opcode = OP_REGOFFSET;
12939                                 tree->inst_basereg = ins->inst_basereg;
12940                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12941
12942                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12943                                 g_assert (tree);
12944                                 tree->opcode = OP_REGOFFSET;
12945                                 tree->inst_basereg = ins->inst_basereg;
12946                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12947                                 break;
12948                         }
12949                         default:
12950                                 break;
12951                         }
12952                 }
12953         }
12954 #endif
12955
12956         if (cfg->compute_gc_maps) {
12957                 /* registers need liveness info even for !non refs */
12958                 for (i = 0; i < cfg->num_varinfo; i++) {
12959                         MonoInst *ins = cfg->varinfo [i];
12960
12961                         if (ins->opcode == OP_REGVAR)
12962                                 ins->flags |= MONO_INST_GC_TRACK;
12963                 }
12964         }
12965
12966         if (cfg->gsharedvt) {
12967                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
12968
12969                 for (i = 0; i < cfg->num_varinfo; ++i) {
12970                         MonoInst *ins = cfg->varinfo [i];
12971                         int idx;
12972
12973                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12974                                 if (i >= cfg->locals_start) {
12975                                         /* Local */
12976                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
12977                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
12978                                         ins->opcode = OP_GSHAREDVT_LOCAL;
12979                                         ins->inst_imm = idx;
12980                                 } else {
12981                                         /* Arg */
12982                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
12983                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
12984                                 }
12985                         }
12986                 }
12987         }
12988                 
12989         /* FIXME: widening and truncation */
12990
12991         /*
12992          * As an optimization, when a variable allocated to the stack is first loaded into 
12993          * an lvreg, we will remember the lvreg and use it the next time instead of loading
12994          * the variable again.
12995          */
12996         orig_next_vreg = cfg->next_vreg;
12997         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
12998         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
12999         lvregs_len = 0;
13000
13001         /* 
13002          * These arrays contain the first and last instructions accessing a given
13003          * variable.
13004          * Since we emit bblocks in the same order we process them here, and we
13005          * don't split live ranges, these will precisely describe the live range of
13006          * the variable, i.e. the instruction range where a valid value can be found
13007          * in the variables location.
13008          * The live range is computed using the liveness info computed by the liveness pass.
13009          * We can't use vmv->range, since that is an abstract live range, and we need
13010          * one which is instruction precise.
13011          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13012          */
13013         /* FIXME: Only do this if debugging info is requested */
13014         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13015         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13016         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13017         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13018         
13019         /* Add spill loads/stores */
13020         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13021                 MonoInst *ins;
13022
13023                 if (cfg->verbose_level > 2)
13024                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13025
13026                 /* Clear vreg_to_lvreg array */
13027                 for (i = 0; i < lvregs_len; i++)
13028                         vreg_to_lvreg [lvregs [i]] = 0;
13029                 lvregs_len = 0;
13030
13031                 cfg->cbb = bb;
13032                 MONO_BB_FOR_EACH_INS (bb, ins) {
13033                         const char *spec = INS_INFO (ins->opcode);
13034                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13035                         gboolean store, no_lvreg;
13036                         int sregs [MONO_MAX_SRC_REGS];
13037
13038                         if (G_UNLIKELY (cfg->verbose_level > 2))
13039                                 mono_print_ins (ins);
13040
13041                         if (ins->opcode == OP_NOP)
13042                                 continue;
13043
13044                         /* 
13045                          * We handle LDADDR here as well, since it can only be decomposed
13046                          * when variable addresses are known.
13047                          */
13048                         if (ins->opcode == OP_LDADDR) {
13049                                 MonoInst *var = ins->inst_p0;
13050
13051                                 if (var->opcode == OP_VTARG_ADDR) {
13052                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13053                                         MonoInst *vtaddr = var->inst_left;
13054                                         if (vtaddr->opcode == OP_REGVAR) {
13055                                                 ins->opcode = OP_MOVE;
13056                                                 ins->sreg1 = vtaddr->dreg;
13057                                         }
13058                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13059                                                 ins->opcode = OP_LOAD_MEMBASE;
13060                                                 ins->inst_basereg = vtaddr->inst_basereg;
13061                                                 ins->inst_offset = vtaddr->inst_offset;
13062                                         } else
13063                                                 NOT_IMPLEMENTED;
13064                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13065                                         /* gsharedvt arg passed by ref */
13066                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13067
13068                                         ins->opcode = OP_LOAD_MEMBASE;
13069                                         ins->inst_basereg = var->inst_basereg;
13070                                         ins->inst_offset = var->inst_offset;
13071                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13072                                         MonoInst *load, *load2, *load3;
13073                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13074                                         int reg1, reg2, reg3;
13075                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13076                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13077
13078                                         /*
13079                                          * gsharedvt local.
13080                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13081                                          */
13082
13083                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13084
13085                                         g_assert (info_var);
13086                                         g_assert (locals_var);
13087
13088                                         /* Mark the instruction used to compute the locals var as used */
13089                                         cfg->gsharedvt_locals_var_ins = NULL;
13090
13091                                         /* Load the offset */
13092                                         if (info_var->opcode == OP_REGOFFSET) {
13093                                                 reg1 = alloc_ireg (cfg);
13094                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13095                                         } else if (info_var->opcode == OP_REGVAR) {
13096                                                 load = NULL;
13097                                                 reg1 = info_var->dreg;
13098                                         } else {
13099                                                 g_assert_not_reached ();
13100                                         }
13101                                         reg2 = alloc_ireg (cfg);
13102                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13103                                         /* Load the locals area address */
13104                                         reg3 = alloc_ireg (cfg);
13105                                         if (locals_var->opcode == OP_REGOFFSET) {
13106                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13107                                         } else if (locals_var->opcode == OP_REGVAR) {
13108                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13109                                         } else {
13110                                                 g_assert_not_reached ();
13111                                         }
13112                                         /* Compute the address */
13113                                         ins->opcode = OP_PADD;
13114                                         ins->sreg1 = reg3;
13115                                         ins->sreg2 = reg2;
13116
13117                                         mono_bblock_insert_before_ins (bb, ins, load3);
13118                                         mono_bblock_insert_before_ins (bb, load3, load2);
13119                                         if (load)
13120                                                 mono_bblock_insert_before_ins (bb, load2, load);
13121                                 } else {
13122                                         g_assert (var->opcode == OP_REGOFFSET);
13123
13124                                         ins->opcode = OP_ADD_IMM;
13125                                         ins->sreg1 = var->inst_basereg;
13126                                         ins->inst_imm = var->inst_offset;
13127                                 }
13128
13129                                 *need_local_opts = TRUE;
13130                                 spec = INS_INFO (ins->opcode);
13131                         }
13132
13133                         if (ins->opcode < MONO_CEE_LAST) {
13134                                 mono_print_ins (ins);
13135                                 g_assert_not_reached ();
13136                         }
13137
13138                         /*
13139                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13140                          * src register.
13141                          * FIXME:
13142                          */
13143                         if (MONO_IS_STORE_MEMBASE (ins)) {
13144                                 tmp_reg = ins->dreg;
13145                                 ins->dreg = ins->sreg2;
13146                                 ins->sreg2 = tmp_reg;
13147                                 store = TRUE;
13148
13149                                 spec2 [MONO_INST_DEST] = ' ';
13150                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13151                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13152                                 spec2 [MONO_INST_SRC3] = ' ';
13153                                 spec = spec2;
13154                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13155                                 g_assert_not_reached ();
13156                         else
13157                                 store = FALSE;
13158                         no_lvreg = FALSE;
13159
13160                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13161                                 printf ("\t %.3s %d", spec, ins->dreg);
13162                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13163                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13164                                         printf (" %d", sregs [srcindex]);
13165                                 printf ("\n");
13166                         }
13167
13168                         /***************/
13169                         /*    DREG     */
13170                         /***************/
13171                         regtype = spec [MONO_INST_DEST];
13172                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13173                         prev_dreg = -1;
13174
13175                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13176                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13177                                 MonoInst *store_ins;
13178                                 int store_opcode;
13179                                 MonoInst *def_ins = ins;
13180                                 int dreg = ins->dreg; /* The original vreg */
13181
13182                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13183
13184                                 if (var->opcode == OP_REGVAR) {
13185                                         ins->dreg = var->dreg;
13186                                 } 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)) {
13187                                         /* 
13188                                          * Instead of emitting a load+store, use a _membase opcode.
13189                                          */
13190                                         g_assert (var->opcode == OP_REGOFFSET);
13191                                         if (ins->opcode == OP_MOVE) {
13192                                                 NULLIFY_INS (ins);
13193                                                 def_ins = NULL;
13194                                         } else {
13195                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13196                                                 ins->inst_basereg = var->inst_basereg;
13197                                                 ins->inst_offset = var->inst_offset;
13198                                                 ins->dreg = -1;
13199                                         }
13200                                         spec = INS_INFO (ins->opcode);
13201                                 } else {
13202                                         guint32 lvreg;
13203
13204                                         g_assert (var->opcode == OP_REGOFFSET);
13205
13206                                         prev_dreg = ins->dreg;
13207
13208                                         /* Invalidate any previous lvreg for this vreg */
13209                                         vreg_to_lvreg [ins->dreg] = 0;
13210
13211                                         lvreg = 0;
13212
13213                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13214                                                 regtype = 'l';
13215                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13216                                         }
13217
13218                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13219
13220 #if SIZEOF_REGISTER != 8
13221                                         if (regtype == 'l') {
13222                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13223                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13224                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13225                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13226                                                 def_ins = store_ins;
13227                                         }
13228                                         else
13229 #endif
13230                                         {
13231                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13232
13233                                                 /* Try to fuse the store into the instruction itself */
13234                                                 /* FIXME: Add more instructions */
13235                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13236                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13237                                                         ins->inst_imm = ins->inst_c0;
13238                                                         ins->inst_destbasereg = var->inst_basereg;
13239                                                         ins->inst_offset = var->inst_offset;
13240                                                         spec = INS_INFO (ins->opcode);
13241                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13242                                                         ins->opcode = store_opcode;
13243                                                         ins->inst_destbasereg = var->inst_basereg;
13244                                                         ins->inst_offset = var->inst_offset;
13245
13246                                                         no_lvreg = TRUE;
13247
13248                                                         tmp_reg = ins->dreg;
13249                                                         ins->dreg = ins->sreg2;
13250                                                         ins->sreg2 = tmp_reg;
13251                                                         store = TRUE;
13252
13253                                                         spec2 [MONO_INST_DEST] = ' ';
13254                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13255                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13256                                                         spec2 [MONO_INST_SRC3] = ' ';
13257                                                         spec = spec2;
13258                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13259                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13260                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13261                                                         ins->dreg = -1;
13262                                                         ins->inst_basereg = var->inst_basereg;
13263                                                         ins->inst_offset = var->inst_offset;
13264                                                         spec = INS_INFO (ins->opcode);
13265                                                 } else {
13266                                                         /* printf ("INS: "); mono_print_ins (ins); */
13267                                                         /* Create a store instruction */
13268                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13269
13270                                                         /* Insert it after the instruction */
13271                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13272
13273                                                         def_ins = store_ins;
13274
13275                                                         /* 
13276                                                          * We can't assign ins->dreg to var->dreg here, since the
13277                                                          * sregs could use it. So set a flag, and do it after
13278                                                          * the sregs.
13279                                                          */
13280                                                         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)))
13281                                                                 dest_has_lvreg = TRUE;
13282                                                 }
13283                                         }
13284                                 }
13285
13286                                 if (def_ins && !live_range_start [dreg]) {
13287                                         live_range_start [dreg] = def_ins;
13288                                         live_range_start_bb [dreg] = bb;
13289                                 }
13290
13291                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13292                                         MonoInst *tmp;
13293
13294                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13295                                         tmp->inst_c1 = dreg;
13296                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13297                                 }
13298                         }
13299
13300                         /************/
13301                         /*  SREGS   */
13302                         /************/
13303                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13304                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13305                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13306                                 sreg = sregs [srcindex];
13307
13308                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13309                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13310                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13311                                         MonoInst *use_ins = ins;
13312                                         MonoInst *load_ins;
13313                                         guint32 load_opcode;
13314
13315                                         if (var->opcode == OP_REGVAR) {
13316                                                 sregs [srcindex] = var->dreg;
13317                                                 //mono_inst_set_src_registers (ins, sregs);
13318                                                 live_range_end [sreg] = use_ins;
13319                                                 live_range_end_bb [sreg] = bb;
13320
13321                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13322                                                         MonoInst *tmp;
13323
13324                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13325                                                         /* var->dreg is a hreg */
13326                                                         tmp->inst_c1 = sreg;
13327                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13328                                                 }
13329
13330                                                 continue;
13331                                         }
13332
13333                                         g_assert (var->opcode == OP_REGOFFSET);
13334                                                 
13335                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13336
13337                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13338
13339                                         if (vreg_to_lvreg [sreg]) {
13340                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13341
13342                                                 /* The variable is already loaded to an lvreg */
13343                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13344                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13345                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13346                                                 //mono_inst_set_src_registers (ins, sregs);
13347                                                 continue;
13348                                         }
13349
13350                                         /* Try to fuse the load into the instruction */
13351                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13352                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13353                                                 sregs [0] = var->inst_basereg;
13354                                                 //mono_inst_set_src_registers (ins, sregs);
13355                                                 ins->inst_offset = var->inst_offset;
13356                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13357                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13358                                                 sregs [1] = var->inst_basereg;
13359                                                 //mono_inst_set_src_registers (ins, sregs);
13360                                                 ins->inst_offset = var->inst_offset;
13361                                         } else {
13362                                                 if (MONO_IS_REAL_MOVE (ins)) {
13363                                                         ins->opcode = OP_NOP;
13364                                                         sreg = ins->dreg;
13365                                                 } else {
13366                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13367
13368                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13369
13370                                                         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) {
13371                                                                 if (var->dreg == prev_dreg) {
13372                                                                         /*
13373                                                                          * sreg refers to the value loaded by the load
13374                                                                          * emitted below, but we need to use ins->dreg
13375                                                                          * since it refers to the store emitted earlier.
13376                                                                          */
13377                                                                         sreg = ins->dreg;
13378                                                                 }
13379                                                                 g_assert (sreg != -1);
13380                                                                 vreg_to_lvreg [var->dreg] = sreg;
13381                                                                 g_assert (lvregs_len < 1024);
13382                                                                 lvregs [lvregs_len ++] = var->dreg;
13383                                                         }
13384                                                 }
13385
13386                                                 sregs [srcindex] = sreg;
13387                                                 //mono_inst_set_src_registers (ins, sregs);
13388
13389 #if SIZEOF_REGISTER != 8
13390                                                 if (regtype == 'l') {
13391                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13392                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13393                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13394                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13395                                                         use_ins = load_ins;
13396                                                 }
13397                                                 else
13398 #endif
13399                                                 {
13400 #if SIZEOF_REGISTER == 4
13401                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13402 #endif
13403                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13404                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13405                                                         use_ins = load_ins;
13406                                                 }
13407                                         }
13408
13409                                         if (var->dreg < orig_next_vreg) {
13410                                                 live_range_end [var->dreg] = use_ins;
13411                                                 live_range_end_bb [var->dreg] = bb;
13412                                         }
13413
13414                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13415                                                 MonoInst *tmp;
13416
13417                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13418                                                 tmp->inst_c1 = var->dreg;
13419                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13420                                         }
13421                                 }
13422                         }
13423                         mono_inst_set_src_registers (ins, sregs);
13424
13425                         if (dest_has_lvreg) {
13426                                 g_assert (ins->dreg != -1);
13427                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13428                                 g_assert (lvregs_len < 1024);
13429                                 lvregs [lvregs_len ++] = prev_dreg;
13430                                 dest_has_lvreg = FALSE;
13431                         }
13432
13433                         if (store) {
13434                                 tmp_reg = ins->dreg;
13435                                 ins->dreg = ins->sreg2;
13436                                 ins->sreg2 = tmp_reg;
13437                         }
13438
13439                         if (MONO_IS_CALL (ins)) {
13440                                 /* Clear vreg_to_lvreg array */
13441                                 for (i = 0; i < lvregs_len; i++)
13442                                         vreg_to_lvreg [lvregs [i]] = 0;
13443                                 lvregs_len = 0;
13444                         } else if (ins->opcode == OP_NOP) {
13445                                 ins->dreg = -1;
13446                                 MONO_INST_NULLIFY_SREGS (ins);
13447                         }
13448
13449                         if (cfg->verbose_level > 2)
13450                                 mono_print_ins_index (1, ins);
13451                 }
13452
13453                 /* Extend the live range based on the liveness info */
13454                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13455                         for (i = 0; i < cfg->num_varinfo; i ++) {
13456                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13457
13458                                 if (vreg_is_volatile (cfg, vi->vreg))
13459                                         /* The liveness info is incomplete */
13460                                         continue;
13461
13462                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13463                                         /* Live from at least the first ins of this bb */
13464                                         live_range_start [vi->vreg] = bb->code;
13465                                         live_range_start_bb [vi->vreg] = bb;
13466                                 }
13467
13468                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13469                                         /* Live at least until the last ins of this bb */
13470                                         live_range_end [vi->vreg] = bb->last_ins;
13471                                         live_range_end_bb [vi->vreg] = bb;
13472                                 }
13473                         }
13474                 }
13475         }
13476         
13477 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13478         /*
13479          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13480          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13481          */
13482         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13483                 for (i = 0; i < cfg->num_varinfo; ++i) {
13484                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13485                         MonoInst *ins;
13486
13487                         if (live_range_start [vreg]) {
13488                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13489                                 ins->inst_c0 = i;
13490                                 ins->inst_c1 = vreg;
13491                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13492                         }
13493                         if (live_range_end [vreg]) {
13494                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13495                                 ins->inst_c0 = i;
13496                                 ins->inst_c1 = vreg;
13497                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13498                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13499                                 else
13500                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13501                         }
13502                 }
13503         }
13504 #endif
13505
13506         if (cfg->gsharedvt_locals_var_ins) {
13507                 /* Nullify if unused */
13508                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13509                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13510         }
13511
13512         g_free (live_range_start);
13513         g_free (live_range_end);
13514         g_free (live_range_start_bb);
13515         g_free (live_range_end_bb);
13516 }
13517
13518 /**
13519  * FIXME:
13520  * - use 'iadd' instead of 'int_add'
13521  * - handling ovf opcodes: decompose in method_to_ir.
13522  * - unify iregs/fregs
13523  *   -> partly done, the missing parts are:
13524  *   - a more complete unification would involve unifying the hregs as well, so
13525  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13526  *     would no longer map to the machine hregs, so the code generators would need to
13527  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13528  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13529  *     fp/non-fp branches speeds it up by about 15%.
13530  * - use sext/zext opcodes instead of shifts
13531  * - add OP_ICALL
13532  * - get rid of TEMPLOADs if possible and use vregs instead
13533  * - clean up usage of OP_P/OP_ opcodes
13534  * - cleanup usage of DUMMY_USE
13535  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13536  *   stack
13537  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13538  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13539  * - make sure handle_stack_args () is called before the branch is emitted
13540  * - when the new IR is done, get rid of all unused stuff
13541  * - COMPARE/BEQ as separate instructions or unify them ?
13542  *   - keeping them separate allows specialized compare instructions like
13543  *     compare_imm, compare_membase
13544  *   - most back ends unify fp compare+branch, fp compare+ceq
13545  * - integrate mono_save_args into inline_method
13546  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13547  * - handle long shift opts on 32 bit platforms somehow: they require 
13548  *   3 sregs (2 for arg1 and 1 for arg2)
13549  * - make byref a 'normal' type.
13550  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13551  *   variable if needed.
13552  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13553  *   like inline_method.
13554  * - remove inlining restrictions
13555  * - fix LNEG and enable cfold of INEG
13556  * - generalize x86 optimizations like ldelema as a peephole optimization
13557  * - add store_mem_imm for amd64
13558  * - optimize the loading of the interruption flag in the managed->native wrappers
13559  * - avoid special handling of OP_NOP in passes
13560  * - move code inserting instructions into one function/macro.
13561  * - try a coalescing phase after liveness analysis
13562  * - add float -> vreg conversion + local optimizations on !x86
13563  * - figure out how to handle decomposed branches during optimizations, ie.
13564  *   compare+branch, op_jump_table+op_br etc.
13565  * - promote RuntimeXHandles to vregs
13566  * - vtype cleanups:
13567  *   - add a NEW_VARLOADA_VREG macro
13568  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13569  *   accessing vtype fields.
13570  * - get rid of I8CONST on 64 bit platforms
13571  * - dealing with the increase in code size due to branches created during opcode
13572  *   decomposition:
13573  *   - use extended basic blocks
13574  *     - all parts of the JIT
13575  *     - handle_global_vregs () && local regalloc
13576  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13577  * - sources of increase in code size:
13578  *   - vtypes
13579  *   - long compares
13580  *   - isinst and castclass
13581  *   - lvregs not allocated to global registers even if used multiple times
13582  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13583  *   meaningful.
13584  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13585  * - add all micro optimizations from the old JIT
13586  * - put tree optimizations into the deadce pass
13587  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13588  *   specific function.
13589  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13590  *   fcompare + branchCC.
13591  * - create a helper function for allocating a stack slot, taking into account 
13592  *   MONO_CFG_HAS_SPILLUP.
13593  * - merge r68207.
13594  * - merge the ia64 switch changes.
13595  * - optimize mono_regstate2_alloc_int/float.
13596  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13597  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13598  *   parts of the tree could be separated by other instructions, killing the tree
13599  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13600  *   instructions if the result of the load is used multiple times ?
13601  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13602  * - LAST MERGE: 108395.
13603  * - when returning vtypes in registers, generate IR and append it to the end of the
13604  *   last bb instead of doing it in the epilog.
13605  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13606  */
13607
13608 /*
13609
13610 NOTES
13611 -----
13612
13613 - When to decompose opcodes:
13614   - earlier: this makes some optimizations hard to implement, since the low level IR
13615   no longer contains the neccessary information. But it is easier to do.
13616   - later: harder to implement, enables more optimizations.
13617 - Branches inside bblocks:
13618   - created when decomposing complex opcodes. 
13619     - branches to another bblock: harmless, but not tracked by the branch 
13620       optimizations, so need to branch to a label at the start of the bblock.
13621     - branches to inside the same bblock: very problematic, trips up the local
13622       reg allocator. Can be fixed by spitting the current bblock, but that is a
13623       complex operation, since some local vregs can become global vregs etc.
13624 - Local/global vregs:
13625   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13626     local register allocator.
13627   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13628     structure, created by mono_create_var (). Assigned to hregs or the stack by
13629     the global register allocator.
13630 - When to do optimizations like alu->alu_imm:
13631   - earlier -> saves work later on since the IR will be smaller/simpler
13632   - later -> can work on more instructions
13633 - Handling of valuetypes:
13634   - When a vtype is pushed on the stack, a new temporary is created, an 
13635     instruction computing its address (LDADDR) is emitted and pushed on
13636     the stack. Need to optimize cases when the vtype is used immediately as in
13637     argument passing, stloc etc.
13638 - Instead of the to_end stuff in the old JIT, simply call the function handling
13639   the values on the stack before emitting the last instruction of the bb.
13640 */
13641
13642 #endif /* DISABLE_JIT */