Merge pull request #955 from ermshiperete/bug-xamarin-10537
[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         if (is_set) {
5053                 return emit_array_store (cfg, eklass, args, FALSE);
5054         } else {
5055                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5056                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5057                 return ins;
5058         }
5059 }
5060
5061 static gboolean
5062 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5063 {
5064         uint32_t align;
5065
5066         //Only allow for valuetypes
5067         if (!param_klass->valuetype || !return_klass->valuetype)
5068                 return FALSE;
5069
5070         //That are blitable
5071         if (param_klass->has_references || return_klass->has_references)
5072                 return FALSE;
5073
5074         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5075         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5076                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5077                 return FALSE;
5078
5079         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5080                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5081                 return FALSE;
5082
5083         //And have the same size
5084         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5085                 return FALSE;
5086         return TRUE;
5087 }
5088
5089 static MonoInst*
5090 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5091 {
5092         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5093         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5094
5095         //Valuetypes that are semantically equivalent
5096         if (is_unsafe_mov_compatible (param_klass, return_klass))
5097                 return args [0];
5098
5099         //Arrays of valuetypes that are semantically equivalent
5100         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5101                 return args [0];
5102
5103         return NULL;
5104 }
5105
5106 static MonoInst*
5107 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5108 {
5109 #ifdef MONO_ARCH_SIMD_INTRINSICS
5110         MonoInst *ins = NULL;
5111
5112         if (cfg->opt & MONO_OPT_SIMD) {
5113                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5114                 if (ins)
5115                         return ins;
5116         }
5117 #endif
5118
5119         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5120 }
5121
5122 static MonoInst*
5123 emit_memory_barrier (MonoCompile *cfg, int kind)
5124 {
5125         MonoInst *ins = NULL;
5126         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5127         MONO_ADD_INS (cfg->cbb, ins);
5128         ins->backend.memory_barrier_kind = kind;
5129
5130         return ins;
5131 }
5132
5133 static MonoInst*
5134 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5135 {
5136         MonoInst *ins = NULL;
5137         int opcode = 0;
5138
5139         /* The LLVM backend supports these intrinsics */
5140         if (cmethod->klass == mono_defaults.math_class) {
5141                 if (strcmp (cmethod->name, "Sin") == 0) {
5142                         opcode = OP_SIN;
5143                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5144                         opcode = OP_COS;
5145                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5146                         opcode = OP_SQRT;
5147                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5148                         opcode = OP_ABS;
5149                 }
5150
5151                 if (opcode) {
5152                         MONO_INST_NEW (cfg, ins, opcode);
5153                         ins->type = STACK_R8;
5154                         ins->dreg = mono_alloc_freg (cfg);
5155                         ins->sreg1 = args [0]->dreg;
5156                         MONO_ADD_INS (cfg->cbb, ins);
5157                 }
5158
5159                 opcode = 0;
5160                 if (cfg->opt & MONO_OPT_CMOV) {
5161                         if (strcmp (cmethod->name, "Min") == 0) {
5162                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5163                                         opcode = OP_IMIN;
5164                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5165                                         opcode = OP_IMIN_UN;
5166                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5167                                         opcode = OP_LMIN;
5168                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5169                                         opcode = OP_LMIN_UN;
5170                         } else if (strcmp (cmethod->name, "Max") == 0) {
5171                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5172                                         opcode = OP_IMAX;
5173                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5174                                         opcode = OP_IMAX_UN;
5175                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5176                                         opcode = OP_LMAX;
5177                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5178                                         opcode = OP_LMAX_UN;
5179                         }
5180                 }
5181
5182                 if (opcode) {
5183                         MONO_INST_NEW (cfg, ins, opcode);
5184                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5185                         ins->dreg = mono_alloc_ireg (cfg);
5186                         ins->sreg1 = args [0]->dreg;
5187                         ins->sreg2 = args [1]->dreg;
5188                         MONO_ADD_INS (cfg->cbb, ins);
5189                 }
5190         }
5191
5192         return ins;
5193 }
5194
5195 static MonoInst*
5196 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5197 {
5198         if (cmethod->klass == mono_defaults.array_class) {
5199                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5200                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5201                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5202                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5203                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5204                         return emit_array_unsafe_mov (cfg, fsig, args);
5205         }
5206
5207         return NULL;
5208 }
5209
5210 static MonoInst*
5211 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5212 {
5213         MonoInst *ins = NULL;
5214         
5215         static MonoClass *runtime_helpers_class = NULL;
5216         if (! runtime_helpers_class)
5217                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5218                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5219
5220         if (cmethod->klass == mono_defaults.string_class) {
5221                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5222                         int dreg = alloc_ireg (cfg);
5223                         int index_reg = alloc_preg (cfg);
5224                         int mult_reg = alloc_preg (cfg);
5225                         int add_reg = alloc_preg (cfg);
5226
5227 #if SIZEOF_REGISTER == 8
5228                         /* The array reg is 64 bits but the index reg is only 32 */
5229                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5230 #else
5231                         index_reg = args [1]->dreg;
5232 #endif  
5233                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5234
5235 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5236                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5237                         add_reg = ins->dreg;
5238                         /* Avoid a warning */
5239                         mult_reg = 0;
5240                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5241                                                                    add_reg, 0);
5242 #else
5243                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5244                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5245                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5246                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5247 #endif
5248                         type_from_op (ins, NULL, NULL);
5249                         return ins;
5250                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5251                         int dreg = alloc_ireg (cfg);
5252                         /* Decompose later to allow more optimizations */
5253                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5254                         ins->type = STACK_I4;
5255                         ins->flags |= MONO_INST_FAULT;
5256                         cfg->cbb->has_array_access = TRUE;
5257                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5258
5259                         return ins;
5260                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5261                         int mult_reg = alloc_preg (cfg);
5262                         int add_reg = alloc_preg (cfg);
5263
5264                         /* The corlib functions check for oob already. */
5265                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5266                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5267                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5268                         return cfg->cbb->last_ins;
5269                 } else 
5270                         return NULL;
5271         } else if (cmethod->klass == mono_defaults.object_class) {
5272
5273                 if (strcmp (cmethod->name, "GetType") == 0) {
5274                         int dreg = alloc_ireg_ref (cfg);
5275                         int vt_reg = alloc_preg (cfg);
5276                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5277                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5278                         type_from_op (ins, NULL, NULL);
5279
5280                         return ins;
5281 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5282                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5283                         int dreg = alloc_ireg (cfg);
5284                         int t1 = alloc_ireg (cfg);
5285         
5286                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5287                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5288                         ins->type = STACK_I4;
5289
5290                         return ins;
5291 #endif
5292                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5293                         MONO_INST_NEW (cfg, ins, OP_NOP);
5294                         MONO_ADD_INS (cfg->cbb, ins);
5295                         return ins;
5296                 } else
5297                         return NULL;
5298         } else if (cmethod->klass == mono_defaults.array_class) {
5299                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5300                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5301
5302 #ifndef MONO_BIG_ARRAYS
5303                 /*
5304                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5305                  * Array methods.
5306                  */
5307                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5308                         int dreg = alloc_ireg (cfg);
5309                         int bounds_reg = alloc_ireg_mp (cfg);
5310                         MonoBasicBlock *end_bb, *szarray_bb;
5311                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5312
5313                         NEW_BBLOCK (cfg, end_bb);
5314                         NEW_BBLOCK (cfg, szarray_bb);
5315
5316                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5317                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5318                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5319                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5320                         /* Non-szarray case */
5321                         if (get_length)
5322                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5323                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5324                         else
5325                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5326                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5327                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5328                         MONO_START_BB (cfg, szarray_bb);
5329                         /* Szarray case */
5330                         if (get_length)
5331                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5332                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5333                         else
5334                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5335                         MONO_START_BB (cfg, end_bb);
5336
5337                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5338                         ins->type = STACK_I4;
5339                         
5340                         return ins;
5341                 }
5342 #endif
5343
5344                 if (cmethod->name [0] != 'g')
5345                         return NULL;
5346
5347                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5348                         int dreg = alloc_ireg (cfg);
5349                         int vtable_reg = alloc_preg (cfg);
5350                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5351                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5352                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5353                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5354                         type_from_op (ins, NULL, NULL);
5355
5356                         return ins;
5357                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5358                         int dreg = alloc_ireg (cfg);
5359
5360                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5361                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5362                         type_from_op (ins, NULL, NULL);
5363
5364                         return ins;
5365                 } else
5366                         return NULL;
5367         } else if (cmethod->klass == runtime_helpers_class) {
5368
5369                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5370                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5371                         return ins;
5372                 } else
5373                         return NULL;
5374         } else if (cmethod->klass == mono_defaults.thread_class) {
5375                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5376                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5377                         MONO_ADD_INS (cfg->cbb, ins);
5378                         return ins;
5379                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5380                         return emit_memory_barrier (cfg, FullBarrier);
5381                 }
5382         } else if (cmethod->klass == mono_defaults.monitor_class) {
5383
5384                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5385 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5386                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5387                         MonoMethod *fast_method = NULL;
5388
5389                         /* Avoid infinite recursion */
5390                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5391                                 return NULL;
5392                                 
5393                         fast_method = mono_monitor_get_fast_path (cmethod);
5394                         if (!fast_method)
5395                                 return NULL;
5396
5397                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5398                 }
5399 #endif
5400
5401 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5402                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5403                         MonoCallInst *call;
5404
5405                         if (COMPILE_LLVM (cfg)) {
5406                                 /* 
5407                                  * Pass the argument normally, the LLVM backend will handle the
5408                                  * calling convention problems.
5409                                  */
5410                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5411                         } else {
5412                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5413                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5414                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5415                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5416                         }
5417
5418                         return (MonoInst*)call;
5419                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5420                         MonoCallInst *call;
5421
5422                         if (COMPILE_LLVM (cfg)) {
5423                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5424                         } else {
5425                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5426                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5427                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5428                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5429                         }
5430
5431                         return (MonoInst*)call;
5432                 }
5433 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5434                 {
5435                 MonoMethod *fast_method = NULL;
5436
5437                 /* Avoid infinite recursion */
5438                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5439                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5440                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5441                         return NULL;
5442
5443                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5444                                 strcmp (cmethod->name, "Exit") == 0)
5445                         fast_method = mono_monitor_get_fast_path (cmethod);
5446                 if (!fast_method)
5447                         return NULL;
5448
5449                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5450                 }
5451 #endif
5452         } else if (cmethod->klass->image == mono_defaults.corlib &&
5453                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5454                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5455                 ins = NULL;
5456
5457 #if SIZEOF_REGISTER == 8
5458                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5459                         /* 64 bit reads are already atomic */
5460                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5461                         ins->dreg = mono_alloc_preg (cfg);
5462                         ins->inst_basereg = args [0]->dreg;
5463                         ins->inst_offset = 0;
5464                         MONO_ADD_INS (cfg->cbb, ins);
5465                 }
5466 #endif
5467
5468 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5469                 if (strcmp (cmethod->name, "Increment") == 0) {
5470                         MonoInst *ins_iconst;
5471                         guint32 opcode = 0;
5472
5473                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5474                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5475                                 cfg->has_atomic_add_new_i4 = TRUE;
5476                         }
5477 #if SIZEOF_REGISTER == 8
5478                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5479                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5480 #endif
5481                         if (opcode) {
5482                                 if (!mono_arch_opcode_supported (opcode))
5483                                         return NULL;
5484                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5485                                 ins_iconst->inst_c0 = 1;
5486                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5487                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5488
5489                                 MONO_INST_NEW (cfg, ins, opcode);
5490                                 ins->dreg = mono_alloc_ireg (cfg);
5491                                 ins->inst_basereg = args [0]->dreg;
5492                                 ins->inst_offset = 0;
5493                                 ins->sreg2 = ins_iconst->dreg;
5494                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5495                                 MONO_ADD_INS (cfg->cbb, ins);
5496                         }
5497                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5498                         MonoInst *ins_iconst;
5499                         guint32 opcode = 0;
5500
5501                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5502                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5503                                 cfg->has_atomic_add_new_i4 = TRUE;
5504                         }
5505 #if SIZEOF_REGISTER == 8
5506                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5507                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5508 #endif
5509                         if (opcode) {
5510                                 if (!mono_arch_opcode_supported (opcode))
5511                                         return NULL;
5512                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5513                                 ins_iconst->inst_c0 = -1;
5514                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5515                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5516
5517                                 MONO_INST_NEW (cfg, ins, opcode);
5518                                 ins->dreg = mono_alloc_ireg (cfg);
5519                                 ins->inst_basereg = args [0]->dreg;
5520                                 ins->inst_offset = 0;
5521                                 ins->sreg2 = ins_iconst->dreg;
5522                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5523                                 MONO_ADD_INS (cfg->cbb, ins);
5524                         }
5525                 } else if (strcmp (cmethod->name, "Add") == 0) {
5526                         guint32 opcode = 0;
5527
5528                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5529                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5530                                 cfg->has_atomic_add_new_i4 = TRUE;
5531                         }
5532 #if SIZEOF_REGISTER == 8
5533                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5534                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5535 #endif
5536                         if (opcode) {
5537                                 if (!mono_arch_opcode_supported (opcode))
5538                                         return NULL;
5539                                 MONO_INST_NEW (cfg, ins, opcode);
5540                                 ins->dreg = mono_alloc_ireg (cfg);
5541                                 ins->inst_basereg = args [0]->dreg;
5542                                 ins->inst_offset = 0;
5543                                 ins->sreg2 = args [1]->dreg;
5544                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5545                                 MONO_ADD_INS (cfg->cbb, ins);
5546                         }
5547                 }
5548 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5549
5550 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5551                 if (strcmp (cmethod->name, "Exchange") == 0) {
5552                         guint32 opcode;
5553                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5554
5555                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5556                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5557                                 cfg->has_atomic_exchange_i4 = TRUE;
5558                         }
5559 #if SIZEOF_REGISTER == 8
5560                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5561                                         (fsig->params [0]->type == MONO_TYPE_I))
5562                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5563 #else
5564                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5565                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5566                                 cfg->has_atomic_exchange_i4 = TRUE;
5567                         }
5568 #endif
5569                         else
5570                                 return NULL;
5571
5572                         if (!mono_arch_opcode_supported (opcode))
5573                                 return NULL;
5574
5575                         MONO_INST_NEW (cfg, ins, opcode);
5576                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5577                         ins->inst_basereg = args [0]->dreg;
5578                         ins->inst_offset = 0;
5579                         ins->sreg2 = args [1]->dreg;
5580                         MONO_ADD_INS (cfg->cbb, ins);
5581
5582                         switch (fsig->params [0]->type) {
5583                         case MONO_TYPE_I4:
5584                                 ins->type = STACK_I4;
5585                                 break;
5586                         case MONO_TYPE_I8:
5587                         case MONO_TYPE_I:
5588                                 ins->type = STACK_I8;
5589                                 break;
5590                         case MONO_TYPE_OBJECT:
5591                                 ins->type = STACK_OBJ;
5592                                 break;
5593                         default:
5594                                 g_assert_not_reached ();
5595                         }
5596
5597                         if (cfg->gen_write_barriers && is_ref)
5598                                 emit_write_barrier (cfg, args [0], args [1]);
5599                 }
5600 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5601  
5602 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5603                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5604                         int size = 0;
5605                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5606                         if (fsig->params [1]->type == MONO_TYPE_I4)
5607                                 size = 4;
5608                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5609                                 size = sizeof (gpointer);
5610                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5611                                 size = 8;
5612                         if (size == 4) {
5613                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5614                                         return NULL;
5615                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5616                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5617                                 ins->sreg1 = args [0]->dreg;
5618                                 ins->sreg2 = args [1]->dreg;
5619                                 ins->sreg3 = args [2]->dreg;
5620                                 ins->type = STACK_I4;
5621                                 MONO_ADD_INS (cfg->cbb, ins);
5622                                 cfg->has_atomic_cas_i4 = TRUE;
5623                         } else if (size == 8) {
5624                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5625                                         return NULL;
5626                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5627                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5628                                 ins->sreg1 = args [0]->dreg;
5629                                 ins->sreg2 = args [1]->dreg;
5630                                 ins->sreg3 = args [2]->dreg;
5631                                 ins->type = STACK_I8;
5632                                 MONO_ADD_INS (cfg->cbb, ins);
5633                         } else {
5634                                 /* g_assert_not_reached (); */
5635                         }
5636                         if (cfg->gen_write_barriers && is_ref)
5637                                 emit_write_barrier (cfg, args [0], args [1]);
5638                 }
5639 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5640
5641                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5642                         ins = emit_memory_barrier (cfg, FullBarrier);
5643
5644                 if (ins)
5645                         return ins;
5646         } else if (cmethod->klass->image == mono_defaults.corlib) {
5647                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5648                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5649                         if (should_insert_brekpoint (cfg->method)) {
5650                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5651                         } else {
5652                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5653                                 MONO_ADD_INS (cfg->cbb, ins);
5654                         }
5655                         return ins;
5656                 }
5657                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5658                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5659 #ifdef TARGET_WIN32
5660                         EMIT_NEW_ICONST (cfg, ins, 1);
5661 #else
5662                         EMIT_NEW_ICONST (cfg, ins, 0);
5663 #endif
5664                         return ins;
5665                 }
5666         } else if (cmethod->klass == mono_defaults.math_class) {
5667                 /* 
5668                  * There is general branches code for Min/Max, but it does not work for 
5669                  * all inputs:
5670                  * http://everything2.com/?node_id=1051618
5671                  */
5672         } 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)) {
5673 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5674                 MonoInst *pi;
5675                 MonoJumpInfoToken *ji;
5676                 MonoString *s;
5677
5678                 cfg->disable_llvm = TRUE;
5679
5680                 if (args [0]->opcode == OP_GOT_ENTRY) {
5681                         pi = args [0]->inst_p1;
5682                         g_assert (pi->opcode == OP_PATCH_INFO);
5683                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5684                         ji = pi->inst_p0;
5685                 } else {
5686                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5687                         ji = args [0]->inst_p0;
5688                 }
5689
5690                 NULLIFY_INS (args [0]);
5691
5692                 // FIXME: Ugly
5693                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5694                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5695                 ins->dreg = mono_alloc_ireg (cfg);
5696                 // FIXME: Leaks
5697                 ins->inst_p0 = mono_string_to_utf8 (s);
5698                 MONO_ADD_INS (cfg->cbb, ins);
5699                 return ins;
5700 #endif
5701         }
5702
5703 #ifdef MONO_ARCH_SIMD_INTRINSICS
5704         if (cfg->opt & MONO_OPT_SIMD) {
5705                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5706                 if (ins)
5707                         return ins;
5708         }
5709 #endif
5710
5711         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5712         if (ins)
5713                 return ins;
5714
5715         if (COMPILE_LLVM (cfg)) {
5716                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5717                 if (ins)
5718                         return ins;
5719         }
5720
5721         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5722 }
5723
5724 /*
5725  * This entry point could be used later for arbitrary method
5726  * redirection.
5727  */
5728 inline static MonoInst*
5729 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5730                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5731 {
5732         if (method->klass == mono_defaults.string_class) {
5733                 /* managed string allocation support */
5734                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5735                         MonoInst *iargs [2];
5736                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5737                         MonoMethod *managed_alloc = NULL;
5738
5739                         g_assert (vtable); /*Should not fail since it System.String*/
5740 #ifndef MONO_CROSS_COMPILE
5741                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5742 #endif
5743                         if (!managed_alloc)
5744                                 return NULL;
5745                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5746                         iargs [1] = args [0];
5747                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5748                 }
5749         }
5750         return NULL;
5751 }
5752
5753 static void
5754 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5755 {
5756         MonoInst *store, *temp;
5757         int i;
5758
5759         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5760                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5761
5762                 /*
5763                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5764                  * would be different than the MonoInst's used to represent arguments, and
5765                  * the ldelema implementation can't deal with that.
5766                  * Solution: When ldelema is used on an inline argument, create a var for 
5767                  * it, emit ldelema on that var, and emit the saving code below in
5768                  * inline_method () if needed.
5769                  */
5770                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5771                 cfg->args [i] = temp;
5772                 /* This uses cfg->args [i] which is set by the preceeding line */
5773                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5774                 store->cil_code = sp [0]->cil_code;
5775                 sp++;
5776         }
5777 }
5778
5779 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5780 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5781
5782 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5783 static gboolean
5784 check_inline_called_method_name_limit (MonoMethod *called_method)
5785 {
5786         int strncmp_result;
5787         static const char *limit = NULL;
5788         
5789         if (limit == NULL) {
5790                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5791
5792                 if (limit_string != NULL)
5793                         limit = limit_string;
5794                 else
5795                         limit = "";
5796         }
5797
5798         if (limit [0] != '\0') {
5799                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5800
5801                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5802                 g_free (called_method_name);
5803         
5804                 //return (strncmp_result <= 0);
5805                 return (strncmp_result == 0);
5806         } else {
5807                 return TRUE;
5808         }
5809 }
5810 #endif
5811
5812 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5813 static gboolean
5814 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5815 {
5816         int strncmp_result;
5817         static const char *limit = NULL;
5818         
5819         if (limit == NULL) {
5820                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5821                 if (limit_string != NULL) {
5822                         limit = limit_string;
5823                 } else {
5824                         limit = "";
5825                 }
5826         }
5827
5828         if (limit [0] != '\0') {
5829                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5830
5831                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5832                 g_free (caller_method_name);
5833         
5834                 //return (strncmp_result <= 0);
5835                 return (strncmp_result == 0);
5836         } else {
5837                 return TRUE;
5838         }
5839 }
5840 #endif
5841
5842 static void
5843 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5844 {
5845         static double r8_0 = 0.0;
5846         MonoInst *ins;
5847         int t;
5848
5849         rtype = mini_replace_type (rtype);
5850         t = rtype->type;
5851
5852         if (rtype->byref) {
5853                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5854         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5855                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5856         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5857                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5858         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5859                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5860                 ins->type = STACK_R8;
5861                 ins->inst_p0 = (void*)&r8_0;
5862                 ins->dreg = dreg;
5863                 MONO_ADD_INS (cfg->cbb, ins);
5864         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5865                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5866                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5867         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5868                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5869         } else {
5870                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5871         }
5872 }
5873
5874 static void
5875 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5876 {
5877         int t;
5878
5879         rtype = mini_replace_type (rtype);
5880         t = rtype->type;
5881
5882         if (rtype->byref) {
5883                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
5884         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5885                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
5886         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5887                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
5888         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5889                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
5890         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5891                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5892                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5893         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5894                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5895         } else {
5896                 emit_init_rvar (cfg, dreg, rtype);
5897         }
5898 }
5899
5900 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
5901 static void
5902 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
5903 {
5904         MonoInst *var = cfg->locals [local];
5905         if (COMPILE_SOFT_FLOAT (cfg)) {
5906                 MonoInst *store;
5907                 int reg = alloc_dreg (cfg, var->type);
5908                 emit_init_rvar (cfg, reg, type);
5909                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5910         } else {
5911                 if (init)
5912                         emit_init_rvar (cfg, var->dreg, type);
5913                 else
5914                         emit_dummy_init_rvar (cfg, var->dreg, type);
5915         }
5916 }
5917
5918 static int
5919 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5920                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5921 {
5922         MonoInst *ins, *rvar = NULL;
5923         MonoMethodHeader *cheader;
5924         MonoBasicBlock *ebblock, *sbblock;
5925         int i, costs;
5926         MonoMethod *prev_inlined_method;
5927         MonoInst **prev_locals, **prev_args;
5928         MonoType **prev_arg_types;
5929         guint prev_real_offset;
5930         GHashTable *prev_cbb_hash;
5931         MonoBasicBlock **prev_cil_offset_to_bb;
5932         MonoBasicBlock *prev_cbb;
5933         unsigned char* prev_cil_start;
5934         guint32 prev_cil_offset_to_bb_len;
5935         MonoMethod *prev_current_method;
5936         MonoGenericContext *prev_generic_context;
5937         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5938
5939         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5940
5941 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5942         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5943                 return 0;
5944 #endif
5945 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5946         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5947                 return 0;
5948 #endif
5949
5950         if (cfg->verbose_level > 2)
5951                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5952
5953         if (!cmethod->inline_info) {
5954                 cfg->stat_inlineable_methods++;
5955                 cmethod->inline_info = 1;
5956         }
5957
5958         /* allocate local variables */
5959         cheader = mono_method_get_header (cmethod);
5960
5961         if (cheader == NULL || mono_loader_get_last_error ()) {
5962                 MonoLoaderError *error = mono_loader_get_last_error ();
5963
5964                 if (cheader)
5965                         mono_metadata_free_mh (cheader);
5966                 if (inline_always && error)
5967                         mono_cfg_set_exception (cfg, error->exception_type);
5968
5969                 mono_loader_clear_error ();
5970                 return 0;
5971         }
5972
5973         /*Must verify before creating locals as it can cause the JIT to assert.*/
5974         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5975                 mono_metadata_free_mh (cheader);
5976                 return 0;
5977         }
5978
5979         /* allocate space to store the return value */
5980         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5981                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5982         }
5983
5984         prev_locals = cfg->locals;
5985         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5986         for (i = 0; i < cheader->num_locals; ++i)
5987                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5988
5989         /* allocate start and end blocks */
5990         /* This is needed so if the inline is aborted, we can clean up */
5991         NEW_BBLOCK (cfg, sbblock);
5992         sbblock->real_offset = real_offset;
5993
5994         NEW_BBLOCK (cfg, ebblock);
5995         ebblock->block_num = cfg->num_bblocks++;
5996         ebblock->real_offset = real_offset;
5997
5998         prev_args = cfg->args;
5999         prev_arg_types = cfg->arg_types;
6000         prev_inlined_method = cfg->inlined_method;
6001         cfg->inlined_method = cmethod;
6002         cfg->ret_var_set = FALSE;
6003         cfg->inline_depth ++;
6004         prev_real_offset = cfg->real_offset;
6005         prev_cbb_hash = cfg->cbb_hash;
6006         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6007         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6008         prev_cil_start = cfg->cil_start;
6009         prev_cbb = cfg->cbb;
6010         prev_current_method = cfg->current_method;
6011         prev_generic_context = cfg->generic_context;
6012         prev_ret_var_set = cfg->ret_var_set;
6013
6014         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6015                 virtual = TRUE;
6016
6017         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
6018
6019         ret_var_set = cfg->ret_var_set;
6020
6021         cfg->inlined_method = prev_inlined_method;
6022         cfg->real_offset = prev_real_offset;
6023         cfg->cbb_hash = prev_cbb_hash;
6024         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6025         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6026         cfg->cil_start = prev_cil_start;
6027         cfg->locals = prev_locals;
6028         cfg->args = prev_args;
6029         cfg->arg_types = prev_arg_types;
6030         cfg->current_method = prev_current_method;
6031         cfg->generic_context = prev_generic_context;
6032         cfg->ret_var_set = prev_ret_var_set;
6033         cfg->inline_depth --;
6034
6035         if ((costs >= 0 && costs < 60) || inline_always) {
6036                 if (cfg->verbose_level > 2)
6037                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6038                 
6039                 cfg->stat_inlined_methods++;
6040
6041                 /* always add some code to avoid block split failures */
6042                 MONO_INST_NEW (cfg, ins, OP_NOP);
6043                 MONO_ADD_INS (prev_cbb, ins);
6044
6045                 prev_cbb->next_bb = sbblock;
6046                 link_bblock (cfg, prev_cbb, sbblock);
6047
6048                 /* 
6049                  * Get rid of the begin and end bblocks if possible to aid local
6050                  * optimizations.
6051                  */
6052                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6053
6054                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6055                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6056
6057                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6058                         MonoBasicBlock *prev = ebblock->in_bb [0];
6059                         mono_merge_basic_blocks (cfg, prev, ebblock);
6060                         cfg->cbb = prev;
6061                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6062                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6063                                 cfg->cbb = prev_cbb;
6064                         }
6065                 } else {
6066                         /* 
6067                          * Its possible that the rvar is set in some prev bblock, but not in others.
6068                          * (#1835).
6069                          */
6070                         if (rvar) {
6071                                 MonoBasicBlock *bb;
6072
6073                                 for (i = 0; i < ebblock->in_count; ++i) {
6074                                         bb = ebblock->in_bb [i];
6075
6076                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6077                                                 cfg->cbb = bb;
6078
6079                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6080                                         }
6081                                 }
6082                         }
6083
6084                         cfg->cbb = ebblock;
6085                 }
6086
6087                 if (rvar) {
6088                         /*
6089                          * If the inlined method contains only a throw, then the ret var is not 
6090                          * set, so set it to a dummy value.
6091                          */
6092                         if (!ret_var_set)
6093                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6094
6095                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6096                         *sp++ = ins;
6097                 }
6098                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6099                 return costs + 1;
6100         } else {
6101                 if (cfg->verbose_level > 2)
6102                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6103                 cfg->exception_type = MONO_EXCEPTION_NONE;
6104                 mono_loader_clear_error ();
6105
6106                 /* This gets rid of the newly added bblocks */
6107                 cfg->cbb = prev_cbb;
6108         }
6109         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6110         return 0;
6111 }
6112
6113 /*
6114  * Some of these comments may well be out-of-date.
6115  * Design decisions: we do a single pass over the IL code (and we do bblock 
6116  * splitting/merging in the few cases when it's required: a back jump to an IL
6117  * address that was not already seen as bblock starting point).
6118  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6119  * Complex operations are decomposed in simpler ones right away. We need to let the 
6120  * arch-specific code peek and poke inside this process somehow (except when the 
6121  * optimizations can take advantage of the full semantic info of coarse opcodes).
6122  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6123  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6124  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6125  * opcode with value bigger than OP_LAST.
6126  * At this point the IR can be handed over to an interpreter, a dumb code generator
6127  * or to the optimizing code generator that will translate it to SSA form.
6128  *
6129  * Profiling directed optimizations.
6130  * We may compile by default with few or no optimizations and instrument the code
6131  * or the user may indicate what methods to optimize the most either in a config file
6132  * or through repeated runs where the compiler applies offline the optimizations to 
6133  * each method and then decides if it was worth it.
6134  */
6135
6136 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6137 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6138 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6139 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6140 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6141 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6142 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6143 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
6144
6145 /* offset from br.s -> br like opcodes */
6146 #define BIG_BRANCH_OFFSET 13
6147
6148 static gboolean
6149 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6150 {
6151         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6152
6153         return b == NULL || b == bb;
6154 }
6155
6156 static int
6157 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6158 {
6159         unsigned char *ip = start;
6160         unsigned char *target;
6161         int i;
6162         guint cli_addr;
6163         MonoBasicBlock *bblock;
6164         const MonoOpcode *opcode;
6165
6166         while (ip < end) {
6167                 cli_addr = ip - start;
6168                 i = mono_opcode_value ((const guint8 **)&ip, end);
6169                 if (i < 0)
6170                         UNVERIFIED;
6171                 opcode = &mono_opcodes [i];
6172                 switch (opcode->argument) {
6173                 case MonoInlineNone:
6174                         ip++; 
6175                         break;
6176                 case MonoInlineString:
6177                 case MonoInlineType:
6178                 case MonoInlineField:
6179                 case MonoInlineMethod:
6180                 case MonoInlineTok:
6181                 case MonoInlineSig:
6182                 case MonoShortInlineR:
6183                 case MonoInlineI:
6184                         ip += 5;
6185                         break;
6186                 case MonoInlineVar:
6187                         ip += 3;
6188                         break;
6189                 case MonoShortInlineVar:
6190                 case MonoShortInlineI:
6191                         ip += 2;
6192                         break;
6193                 case MonoShortInlineBrTarget:
6194                         target = start + cli_addr + 2 + (signed char)ip [1];
6195                         GET_BBLOCK (cfg, bblock, target);
6196                         ip += 2;
6197                         if (ip < end)
6198                                 GET_BBLOCK (cfg, bblock, ip);
6199                         break;
6200                 case MonoInlineBrTarget:
6201                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6202                         GET_BBLOCK (cfg, bblock, target);
6203                         ip += 5;
6204                         if (ip < end)
6205                                 GET_BBLOCK (cfg, bblock, ip);
6206                         break;
6207                 case MonoInlineSwitch: {
6208                         guint32 n = read32 (ip + 1);
6209                         guint32 j;
6210                         ip += 5;
6211                         cli_addr += 5 + 4 * n;
6212                         target = start + cli_addr;
6213                         GET_BBLOCK (cfg, bblock, target);
6214                         
6215                         for (j = 0; j < n; ++j) {
6216                                 target = start + cli_addr + (gint32)read32 (ip);
6217                                 GET_BBLOCK (cfg, bblock, target);
6218                                 ip += 4;
6219                         }
6220                         break;
6221                 }
6222                 case MonoInlineR:
6223                 case MonoInlineI8:
6224                         ip += 9;
6225                         break;
6226                 default:
6227                         g_assert_not_reached ();
6228                 }
6229
6230                 if (i == CEE_THROW) {
6231                         unsigned char *bb_start = ip - 1;
6232                         
6233                         /* Find the start of the bblock containing the throw */
6234                         bblock = NULL;
6235                         while ((bb_start >= start) && !bblock) {
6236                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6237                                 bb_start --;
6238                         }
6239                         if (bblock)
6240                                 bblock->out_of_line = 1;
6241                 }
6242         }
6243         return 0;
6244 unverified:
6245 exception_exit:
6246         *pos = ip;
6247         return 1;
6248 }
6249
6250 static inline MonoMethod *
6251 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6252 {
6253         MonoMethod *method;
6254
6255         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6256                 method = mono_method_get_wrapper_data (m, token);
6257                 if (context)
6258                         method = mono_class_inflate_generic_method (method, context);
6259         } else {
6260                 method = mono_get_method_full (m->klass->image, token, klass, context);
6261         }
6262
6263         return method;
6264 }
6265
6266 static inline MonoMethod *
6267 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6268 {
6269         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6270
6271         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6272                 return NULL;
6273
6274         return method;
6275 }
6276
6277 static inline MonoClass*
6278 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6279 {
6280         MonoClass *klass;
6281
6282         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6283                 klass = mono_method_get_wrapper_data (method, token);
6284                 if (context)
6285                         klass = mono_class_inflate_generic_class (klass, context);
6286         } else {
6287                 klass = mono_class_get_full (method->klass->image, token, context);
6288         }
6289         if (klass)
6290                 mono_class_init (klass);
6291         return klass;
6292 }
6293
6294 static inline MonoMethodSignature*
6295 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6296 {
6297         MonoMethodSignature *fsig;
6298
6299         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6300                 MonoError error;
6301
6302                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6303                 if (context) {
6304                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6305                         // FIXME:
6306                         g_assert (mono_error_ok (&error));
6307                 }
6308         } else {
6309                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6310         }
6311         return fsig;
6312 }
6313
6314 /*
6315  * Returns TRUE if the JIT should abort inlining because "callee"
6316  * is influenced by security attributes.
6317  */
6318 static
6319 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6320 {
6321         guint32 result;
6322         
6323         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6324                 return TRUE;
6325         }
6326         
6327         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6328         if (result == MONO_JIT_SECURITY_OK)
6329                 return FALSE;
6330
6331         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6332                 /* Generate code to throw a SecurityException before the actual call/link */
6333                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6334                 MonoInst *args [2];
6335
6336                 NEW_ICONST (cfg, args [0], 4);
6337                 NEW_METHODCONST (cfg, args [1], caller);
6338                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6339         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6340                  /* don't hide previous results */
6341                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6342                 cfg->exception_data = result;
6343                 return TRUE;
6344         }
6345         
6346         return FALSE;
6347 }
6348
6349 static MonoMethod*
6350 throw_exception (void)
6351 {
6352         static MonoMethod *method = NULL;
6353
6354         if (!method) {
6355                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6356                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6357         }
6358         g_assert (method);
6359         return method;
6360 }
6361
6362 static void
6363 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6364 {
6365         MonoMethod *thrower = throw_exception ();
6366         MonoInst *args [1];
6367
6368         EMIT_NEW_PCONST (cfg, args [0], ex);
6369         mono_emit_method_call (cfg, thrower, args, NULL);
6370 }
6371
6372 /*
6373  * Return the original method is a wrapper is specified. We can only access 
6374  * the custom attributes from the original method.
6375  */
6376 static MonoMethod*
6377 get_original_method (MonoMethod *method)
6378 {
6379         if (method->wrapper_type == MONO_WRAPPER_NONE)
6380                 return method;
6381
6382         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6383         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6384                 return NULL;
6385
6386         /* in other cases we need to find the original method */
6387         return mono_marshal_method_from_wrapper (method);
6388 }
6389
6390 static void
6391 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6392                                           MonoBasicBlock *bblock, unsigned char *ip)
6393 {
6394         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6395         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6396         if (ex)
6397                 emit_throw_exception (cfg, ex);
6398 }
6399
6400 static void
6401 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6402                                          MonoBasicBlock *bblock, unsigned char *ip)
6403 {
6404         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6405         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6406         if (ex)
6407                 emit_throw_exception (cfg, ex);
6408 }
6409
6410 /*
6411  * Check that the IL instructions at ip are the array initialization
6412  * sequence and return the pointer to the data and the size.
6413  */
6414 static const char*
6415 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6416 {
6417         /*
6418          * newarr[System.Int32]
6419          * dup
6420          * ldtoken field valuetype ...
6421          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6422          */
6423         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6424                 guint32 token = read32 (ip + 7);
6425                 guint32 field_token = read32 (ip + 2);
6426                 guint32 field_index = field_token & 0xffffff;
6427                 guint32 rva;
6428                 const char *data_ptr;
6429                 int size = 0;
6430                 MonoMethod *cmethod;
6431                 MonoClass *dummy_class;
6432                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6433                 int dummy_align;
6434
6435                 if (!field)
6436                         return NULL;
6437
6438                 *out_field_token = field_token;
6439
6440                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6441                 if (!cmethod)
6442                         return NULL;
6443                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6444                         return NULL;
6445                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6446                 case MONO_TYPE_BOOLEAN:
6447                 case MONO_TYPE_I1:
6448                 case MONO_TYPE_U1:
6449                         size = 1; break;
6450                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6451 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6452                 case MONO_TYPE_CHAR:
6453                 case MONO_TYPE_I2:
6454                 case MONO_TYPE_U2:
6455                         size = 2; break;
6456                 case MONO_TYPE_I4:
6457                 case MONO_TYPE_U4:
6458                 case MONO_TYPE_R4:
6459                         size = 4; break;
6460                 case MONO_TYPE_R8:
6461                 case MONO_TYPE_I8:
6462                 case MONO_TYPE_U8:
6463                         size = 8; break;
6464 #endif
6465                 default:
6466                         return NULL;
6467                 }
6468                 size *= len;
6469                 if (size > mono_type_size (field->type, &dummy_align))
6470                     return NULL;
6471                 *out_size = size;
6472                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6473                 if (!method->klass->image->dynamic) {
6474                         field_index = read32 (ip + 2) & 0xffffff;
6475                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6476                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6477                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6478                         /* for aot code we do the lookup on load */
6479                         if (aot && data_ptr)
6480                                 return GUINT_TO_POINTER (rva);
6481                 } else {
6482                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6483                         g_assert (!aot);
6484                         data_ptr = mono_field_get_data (field);
6485                 }
6486                 return data_ptr;
6487         }
6488         return NULL;
6489 }
6490
6491 static void
6492 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6493 {
6494         char *method_fname = mono_method_full_name (method, TRUE);
6495         char *method_code;
6496         MonoMethodHeader *header = mono_method_get_header (method);
6497
6498         if (header->code_size == 0)
6499                 method_code = g_strdup ("method body is empty.");
6500         else
6501                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6502         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6503         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6504         g_free (method_fname);
6505         g_free (method_code);
6506         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6507 }
6508
6509 static void
6510 set_exception_object (MonoCompile *cfg, MonoException *exception)
6511 {
6512         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6513         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6514         cfg->exception_ptr = exception;
6515 }
6516
6517 static void
6518 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6519 {
6520         MonoInst *ins;
6521         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6522         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6523                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6524                 /* Optimize reg-reg moves away */
6525                 /* 
6526                  * Can't optimize other opcodes, since sp[0] might point to
6527                  * the last ins of a decomposed opcode.
6528                  */
6529                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6530         } else {
6531                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6532         }
6533 }
6534
6535 /*
6536  * ldloca inhibits many optimizations so try to get rid of it in common
6537  * cases.
6538  */
6539 static inline unsigned char *
6540 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6541 {
6542         int local, token;
6543         MonoClass *klass;
6544         MonoType *type;
6545
6546         if (size == 1) {
6547                 local = ip [1];
6548                 ip += 2;
6549         } else {
6550                 local = read16 (ip + 2);
6551                 ip += 4;
6552         }
6553         
6554         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6555                 /* From the INITOBJ case */
6556                 token = read32 (ip + 2);
6557                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6558                 CHECK_TYPELOAD (klass);
6559                 type = mini_replace_type (&klass->byval_arg);
6560                 emit_init_local (cfg, local, type, TRUE);
6561                 return ip + 6;
6562         }
6563 load_error:
6564         return NULL;
6565 }
6566
6567 static gboolean
6568 is_exception_class (MonoClass *class)
6569 {
6570         while (class) {
6571                 if (class == mono_defaults.exception_class)
6572                         return TRUE;
6573                 class = class->parent;
6574         }
6575         return FALSE;
6576 }
6577
6578 /*
6579  * is_jit_optimizer_disabled:
6580  *
6581  *   Determine whenever M's assembly has a DebuggableAttribute with the
6582  * IsJITOptimizerDisabled flag set.
6583  */
6584 static gboolean
6585 is_jit_optimizer_disabled (MonoMethod *m)
6586 {
6587         MonoAssembly *ass = m->klass->image->assembly;
6588         MonoCustomAttrInfo* attrs;
6589         static MonoClass *klass;
6590         int i;
6591         gboolean val = FALSE;
6592
6593         g_assert (ass);
6594         if (ass->jit_optimizer_disabled_inited)
6595                 return ass->jit_optimizer_disabled;
6596
6597         if (!klass)
6598                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6599         if (!klass) {
6600                 /* Linked away */
6601                 ass->jit_optimizer_disabled = FALSE;
6602                 mono_memory_barrier ();
6603                 ass->jit_optimizer_disabled_inited = TRUE;
6604                 return FALSE;
6605         }
6606
6607         attrs = mono_custom_attrs_from_assembly (ass);
6608         if (attrs) {
6609                 for (i = 0; i < attrs->num_attrs; ++i) {
6610                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6611                         const gchar *p;
6612                         int len;
6613                         MonoMethodSignature *sig;
6614
6615                         if (!attr->ctor || attr->ctor->klass != klass)
6616                                 continue;
6617                         /* Decode the attribute. See reflection.c */
6618                         len = attr->data_size;
6619                         p = (const char*)attr->data;
6620                         g_assert (read16 (p) == 0x0001);
6621                         p += 2;
6622
6623                         // FIXME: Support named parameters
6624                         sig = mono_method_signature (attr->ctor);
6625                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6626                                 continue;
6627                         /* Two boolean arguments */
6628                         p ++;
6629                         val = *p;
6630                 }
6631                 mono_custom_attrs_free (attrs);
6632         }
6633
6634         ass->jit_optimizer_disabled = val;
6635         mono_memory_barrier ();
6636         ass->jit_optimizer_disabled_inited = TRUE;
6637
6638         return val;
6639 }
6640
6641 static gboolean
6642 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6643 {
6644         gboolean supported_tail_call;
6645         int i;
6646
6647 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6648         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6649 #else
6650         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6651 #endif
6652
6653         for (i = 0; i < fsig->param_count; ++i) {
6654                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6655                         /* These can point to the current method's stack */
6656                         supported_tail_call = FALSE;
6657         }
6658         if (fsig->hasthis && cmethod->klass->valuetype)
6659                 /* this might point to the current method's stack */
6660                 supported_tail_call = FALSE;
6661         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6662                 supported_tail_call = FALSE;
6663         if (cfg->method->save_lmf)
6664                 supported_tail_call = FALSE;
6665         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6666                 supported_tail_call = FALSE;
6667         if (call_opcode != CEE_CALL)
6668                 supported_tail_call = FALSE;
6669
6670         /* Debugging support */
6671 #if 0
6672         if (supported_tail_call) {
6673                 if (!mono_debug_count ())
6674                         supported_tail_call = FALSE;
6675         }
6676 #endif
6677
6678         return supported_tail_call;
6679 }
6680
6681 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6682  * it to the thread local value based on the tls_offset field. Every other kind of access to
6683  * the field causes an assert.
6684  */
6685 static gboolean
6686 is_magic_tls_access (MonoClassField *field)
6687 {
6688         if (strcmp (field->name, "tlsdata"))
6689                 return FALSE;
6690         if (strcmp (field->parent->name, "ThreadLocal`1"))
6691                 return FALSE;
6692         return field->parent->image == mono_defaults.corlib;
6693 }
6694
6695 /* emits the code needed to access a managed tls var (like ThreadStatic)
6696  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6697  * pointer for the current thread.
6698  * Returns the MonoInst* representing the address of the tls var.
6699  */
6700 static MonoInst*
6701 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6702 {
6703         MonoInst *addr;
6704         int static_data_reg, array_reg, dreg;
6705         int offset2_reg, idx_reg;
6706         // inlined access to the tls data
6707         // idx = (offset >> 24) - 1;
6708         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6709         static_data_reg = alloc_ireg (cfg);
6710         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6711         idx_reg = alloc_ireg (cfg);
6712         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6713         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6714         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6715         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6716         array_reg = alloc_ireg (cfg);
6717         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6718         offset2_reg = alloc_ireg (cfg);
6719         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6720         dreg = alloc_ireg (cfg);
6721         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6722         return addr;
6723 }
6724
6725 /*
6726  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6727  * this address is cached per-method in cached_tls_addr.
6728  */
6729 static MonoInst*
6730 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6731 {
6732         MonoInst *load, *addr, *temp, *store, *thread_ins;
6733         MonoClassField *offset_field;
6734
6735         if (*cached_tls_addr) {
6736                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6737                 return addr;
6738         }
6739         thread_ins = mono_get_thread_intrinsic (cfg);
6740         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6741
6742         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6743         if (thread_ins) {
6744                 MONO_ADD_INS (cfg->cbb, thread_ins);
6745         } else {
6746                 MonoMethod *thread_method;
6747                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6748                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6749         }
6750         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6751         addr->klass = mono_class_from_mono_type (tls_field->type);
6752         addr->type = STACK_MP;
6753         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6754         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6755
6756         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6757         return addr;
6758 }
6759
6760 /*
6761  * mono_method_to_ir:
6762  *
6763  *   Translate the .net IL into linear IR.
6764  */
6765 int
6766 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6767                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6768                    guint inline_offset, gboolean is_virtual_call)
6769 {
6770         MonoError error;
6771         MonoInst *ins, **sp, **stack_start;
6772         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6773         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6774         MonoMethod *cmethod, *method_definition;
6775         MonoInst **arg_array;
6776         MonoMethodHeader *header;
6777         MonoImage *image;
6778         guint32 token, ins_flag;
6779         MonoClass *klass;
6780         MonoClass *constrained_call = NULL;
6781         unsigned char *ip, *end, *target, *err_pos;
6782         MonoMethodSignature *sig;
6783         MonoGenericContext *generic_context = NULL;
6784         MonoGenericContainer *generic_container = NULL;
6785         MonoType **param_types;
6786         int i, n, start_new_bblock, dreg;
6787         int num_calls = 0, inline_costs = 0;
6788         int breakpoint_id = 0;
6789         guint num_args;
6790         MonoBoolean security, pinvoke;
6791         MonoSecurityManager* secman = NULL;
6792         MonoDeclSecurityActions actions;
6793         GSList *class_inits = NULL;
6794         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6795         int context_used;
6796         gboolean init_locals, seq_points, skip_dead_blocks;
6797         gboolean disable_inline, sym_seq_points = FALSE;
6798         MonoInst *cached_tls_addr = NULL;
6799         MonoDebugMethodInfo *minfo;
6800         MonoBitSet *seq_point_locs = NULL;
6801         MonoBitSet *seq_point_set_locs = NULL;
6802
6803         disable_inline = is_jit_optimizer_disabled (method);
6804
6805         /* serialization and xdomain stuff may need access to private fields and methods */
6806         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6807         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6808         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6809         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6810         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6811         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6812
6813         dont_verify |= mono_security_smcs_hack_enabled ();
6814
6815         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6816         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6817         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6818         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6819         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6820
6821         image = method->klass->image;
6822         header = mono_method_get_header (method);
6823         if (!header) {
6824                 MonoLoaderError *error;
6825
6826                 if ((error = mono_loader_get_last_error ())) {
6827                         mono_cfg_set_exception (cfg, error->exception_type);
6828                 } else {
6829                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6830                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6831                 }
6832                 goto exception_exit;
6833         }
6834         generic_container = mono_method_get_generic_container (method);
6835         sig = mono_method_signature (method);
6836         num_args = sig->hasthis + sig->param_count;
6837         ip = (unsigned char*)header->code;
6838         cfg->cil_start = ip;
6839         end = ip + header->code_size;
6840         cfg->stat_cil_code_size += header->code_size;
6841
6842         seq_points = cfg->gen_seq_points && cfg->method == method;
6843 #ifdef PLATFORM_ANDROID
6844         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6845 #endif
6846
6847         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6848                 /* We could hit a seq point before attaching to the JIT (#8338) */
6849                 seq_points = FALSE;
6850         }
6851
6852         if (cfg->gen_seq_points && cfg->method == method) {
6853                 minfo = mono_debug_lookup_method (method);
6854                 if (minfo) {
6855                         int i, n_il_offsets;
6856                         int *il_offsets;
6857                         int *line_numbers;
6858
6859                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6860                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6861                         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);
6862                         sym_seq_points = TRUE;
6863                         for (i = 0; i < n_il_offsets; ++i) {
6864                                 if (il_offsets [i] < header->code_size)
6865                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6866                         }
6867                         g_free (il_offsets);
6868                         g_free (line_numbers);
6869                 }
6870         }
6871
6872         /* 
6873          * Methods without init_locals set could cause asserts in various passes
6874          * (#497220). To work around this, we emit dummy initialization opcodes
6875          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
6876          * on some platforms.
6877          */
6878         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
6879                 init_locals = header->init_locals;
6880         else
6881                 init_locals = TRUE;
6882
6883         method_definition = method;
6884         while (method_definition->is_inflated) {
6885                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6886                 method_definition = imethod->declaring;
6887         }
6888
6889         /* SkipVerification is not allowed if core-clr is enabled */
6890         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6891                 dont_verify = TRUE;
6892                 dont_verify_stloc = TRUE;
6893         }
6894
6895         if (sig->is_inflated)
6896                 generic_context = mono_method_get_context (method);
6897         else if (generic_container)
6898                 generic_context = &generic_container->context;
6899         cfg->generic_context = generic_context;
6900
6901         if (!cfg->generic_sharing_context)
6902                 g_assert (!sig->has_type_parameters);
6903
6904         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6905                 g_assert (method->is_inflated);
6906                 g_assert (mono_method_get_context (method)->method_inst);
6907         }
6908         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6909                 g_assert (sig->generic_param_count);
6910
6911         if (cfg->method == method) {
6912                 cfg->real_offset = 0;
6913         } else {
6914                 cfg->real_offset = inline_offset;
6915         }
6916
6917         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6918         cfg->cil_offset_to_bb_len = header->code_size;
6919
6920         cfg->current_method = method;
6921
6922         if (cfg->verbose_level > 2)
6923                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6924
6925         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6926         if (sig->hasthis)
6927                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6928         for (n = 0; n < sig->param_count; ++n)
6929                 param_types [n + sig->hasthis] = sig->params [n];
6930         cfg->arg_types = param_types;
6931
6932         dont_inline = g_list_prepend (dont_inline, method);
6933         if (cfg->method == method) {
6934
6935                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6936                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6937
6938                 /* ENTRY BLOCK */
6939                 NEW_BBLOCK (cfg, start_bblock);
6940                 cfg->bb_entry = start_bblock;
6941                 start_bblock->cil_code = NULL;
6942                 start_bblock->cil_length = 0;
6943 #if defined(__native_client_codegen__)
6944                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6945                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6946                 MONO_ADD_INS (start_bblock, ins);
6947 #endif
6948
6949                 /* EXIT BLOCK */
6950                 NEW_BBLOCK (cfg, end_bblock);
6951                 cfg->bb_exit = end_bblock;
6952                 end_bblock->cil_code = NULL;
6953                 end_bblock->cil_length = 0;
6954                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6955                 g_assert (cfg->num_bblocks == 2);
6956
6957                 arg_array = cfg->args;
6958
6959                 if (header->num_clauses) {
6960                         cfg->spvars = g_hash_table_new (NULL, NULL);
6961                         cfg->exvars = g_hash_table_new (NULL, NULL);
6962                 }
6963                 /* handle exception clauses */
6964                 for (i = 0; i < header->num_clauses; ++i) {
6965                         MonoBasicBlock *try_bb;
6966                         MonoExceptionClause *clause = &header->clauses [i];
6967                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6968                         try_bb->real_offset = clause->try_offset;
6969                         try_bb->try_start = TRUE;
6970                         try_bb->region = ((i + 1) << 8) | clause->flags;
6971                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6972                         tblock->real_offset = clause->handler_offset;
6973                         tblock->flags |= BB_EXCEPTION_HANDLER;
6974
6975                         /*
6976                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6977                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
6978                          */
6979                         if (COMPILE_LLVM (cfg))
6980                                 link_bblock (cfg, try_bb, tblock);
6981
6982                         if (*(ip + clause->handler_offset) == CEE_POP)
6983                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6984
6985                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6986                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6987                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6988                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6989                                 MONO_ADD_INS (tblock, ins);
6990
6991                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6992                                         /* finally clauses already have a seq point */
6993                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6994                                         MONO_ADD_INS (tblock, ins);
6995                                 }
6996
6997                                 /* todo: is a fault block unsafe to optimize? */
6998                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6999                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7000                         }
7001
7002
7003                         /*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);
7004                           while (p < end) {
7005                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7006                           }*/
7007                         /* catch and filter blocks get the exception object on the stack */
7008                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7009                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7010                                 MonoInst *dummy_use;
7011
7012                                 /* mostly like handle_stack_args (), but just sets the input args */
7013                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7014                                 tblock->in_scount = 1;
7015                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7016                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7017
7018                                 /* 
7019                                  * Add a dummy use for the exvar so its liveness info will be
7020                                  * correct.
7021                                  */
7022                                 cfg->cbb = tblock;
7023                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7024                                 
7025                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7026                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7027                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7028                                         tblock->real_offset = clause->data.filter_offset;
7029                                         tblock->in_scount = 1;
7030                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7031                                         /* The filter block shares the exvar with the handler block */
7032                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7033                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7034                                         MONO_ADD_INS (tblock, ins);
7035                                 }
7036                         }
7037
7038                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7039                                         clause->data.catch_class &&
7040                                         cfg->generic_sharing_context &&
7041                                         mono_class_check_context_used (clause->data.catch_class)) {
7042                                 /*
7043                                  * In shared generic code with catch
7044                                  * clauses containing type variables
7045                                  * the exception handling code has to
7046                                  * be able to get to the rgctx.
7047                                  * Therefore we have to make sure that
7048                                  * the vtable/mrgctx argument (for
7049                                  * static or generic methods) or the
7050                                  * "this" argument (for non-static
7051                                  * methods) are live.
7052                                  */
7053                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7054                                                 mini_method_get_context (method)->method_inst ||
7055                                                 method->klass->valuetype) {
7056                                         mono_get_vtable_var (cfg);
7057                                 } else {
7058                                         MonoInst *dummy_use;
7059
7060                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7061                                 }
7062                         }
7063                 }
7064         } else {
7065                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7066                 cfg->cbb = start_bblock;
7067                 cfg->args = arg_array;
7068                 mono_save_args (cfg, sig, inline_args);
7069         }
7070
7071         /* FIRST CODE BLOCK */
7072         NEW_BBLOCK (cfg, bblock);
7073         bblock->cil_code = ip;
7074         cfg->cbb = bblock;
7075         cfg->ip = ip;
7076
7077         ADD_BBLOCK (cfg, bblock);
7078
7079         if (cfg->method == method) {
7080                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7081                 if (breakpoint_id) {
7082                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7083                         MONO_ADD_INS (bblock, ins);
7084                 }
7085         }
7086
7087         if (mono_security_cas_enabled ())
7088                 secman = mono_security_manager_get_methods ();
7089
7090         security = (secman && mono_security_method_has_declsec (method));
7091         /* at this point having security doesn't mean we have any code to generate */
7092         if (security && (cfg->method == method)) {
7093                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7094                  * And we do not want to enter the next section (with allocation) if we
7095                  * have nothing to generate */
7096                 security = mono_declsec_get_demands (method, &actions);
7097         }
7098
7099         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7100         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7101         if (pinvoke) {
7102                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7103                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7104                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7105
7106                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7107                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7108                                 pinvoke = FALSE;
7109                         }
7110                         if (custom)
7111                                 mono_custom_attrs_free (custom);
7112
7113                         if (pinvoke) {
7114                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7115                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7116                                         pinvoke = FALSE;
7117                                 }
7118                                 if (custom)
7119                                         mono_custom_attrs_free (custom);
7120                         }
7121                 } else {
7122                         /* not a P/Invoke after all */
7123                         pinvoke = FALSE;
7124                 }
7125         }
7126         
7127         /* we use a separate basic block for the initialization code */
7128         NEW_BBLOCK (cfg, init_localsbb);
7129         cfg->bb_init = init_localsbb;
7130         init_localsbb->real_offset = cfg->real_offset;
7131         start_bblock->next_bb = init_localsbb;
7132         init_localsbb->next_bb = bblock;
7133         link_bblock (cfg, start_bblock, init_localsbb);
7134         link_bblock (cfg, init_localsbb, bblock);
7135                 
7136         cfg->cbb = init_localsbb;
7137
7138         if (cfg->gsharedvt && cfg->method == method) {
7139                 MonoGSharedVtMethodInfo *info;
7140                 MonoInst *var, *locals_var;
7141                 int dreg;
7142
7143                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7144                 info->method = cfg->method;
7145                 info->count_entries = 16;
7146                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7147                 cfg->gsharedvt_info = info;
7148
7149                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7150                 /* prevent it from being register allocated */
7151                 //var->flags |= MONO_INST_VOLATILE;
7152                 cfg->gsharedvt_info_var = var;
7153
7154                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7155                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7156
7157                 /* Allocate locals */
7158                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7159                 /* prevent it from being register allocated */
7160                 //locals_var->flags |= MONO_INST_VOLATILE;
7161                 cfg->gsharedvt_locals_var = locals_var;
7162
7163                 dreg = alloc_ireg (cfg);
7164                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7165
7166                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7167                 ins->dreg = locals_var->dreg;
7168                 ins->sreg1 = dreg;
7169                 MONO_ADD_INS (cfg->cbb, ins);
7170                 cfg->gsharedvt_locals_var_ins = ins;
7171                 
7172                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7173                 /*
7174                 if (init_locals)
7175                         ins->flags |= MONO_INST_INIT;
7176                 */
7177         }
7178
7179         /* at this point we know, if security is TRUE, that some code needs to be generated */
7180         if (security && (cfg->method == method)) {
7181                 MonoInst *args [2];
7182
7183                 cfg->stat_cas_demand_generation++;
7184
7185                 if (actions.demand.blob) {
7186                         /* Add code for SecurityAction.Demand */
7187                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7188                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7189                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7190                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7191                 }
7192                 if (actions.noncasdemand.blob) {
7193                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7194                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7195                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7196                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7197                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7198                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7199                 }
7200                 if (actions.demandchoice.blob) {
7201                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7202                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7203                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7204                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7205                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7206                 }
7207         }
7208
7209         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7210         if (pinvoke) {
7211                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7212         }
7213
7214         if (mono_security_core_clr_enabled ()) {
7215                 /* check if this is native code, e.g. an icall or a p/invoke */
7216                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7217                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7218                         if (wrapped) {
7219                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7220                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7221
7222                                 /* if this ia a native call then it can only be JITted from platform code */
7223                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7224                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7225                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7226                                                         mono_get_exception_method_access ();
7227                                                 emit_throw_exception (cfg, ex);
7228                                         }
7229                                 }
7230                         }
7231                 }
7232         }
7233
7234         CHECK_CFG_EXCEPTION;
7235
7236         if (header->code_size == 0)
7237                 UNVERIFIED;
7238
7239         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7240                 ip = err_pos;
7241                 UNVERIFIED;
7242         }
7243
7244         if (cfg->method == method)
7245                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7246
7247         for (n = 0; n < header->num_locals; ++n) {
7248                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7249                         UNVERIFIED;
7250         }
7251         class_inits = NULL;
7252
7253         /* We force the vtable variable here for all shared methods
7254            for the possibility that they might show up in a stack
7255            trace where their exact instantiation is needed. */
7256         if (cfg->generic_sharing_context && method == cfg->method) {
7257                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7258                                 mini_method_get_context (method)->method_inst ||
7259                                 method->klass->valuetype) {
7260                         mono_get_vtable_var (cfg);
7261                 } else {
7262                         /* FIXME: Is there a better way to do this?
7263                            We need the variable live for the duration
7264                            of the whole method. */
7265                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7266                 }
7267         }
7268
7269         /* add a check for this != NULL to inlined methods */
7270         if (is_virtual_call) {
7271                 MonoInst *arg_ins;
7272
7273                 NEW_ARGLOAD (cfg, arg_ins, 0);
7274                 MONO_ADD_INS (cfg->cbb, arg_ins);
7275                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7276         }
7277
7278         skip_dead_blocks = !dont_verify;
7279         if (skip_dead_blocks) {
7280                 original_bb = bb = mono_basic_block_split (method, &error);
7281                 if (!mono_error_ok (&error)) {
7282                         mono_error_cleanup (&error);
7283                         UNVERIFIED;
7284                 }
7285                 g_assert (bb);
7286         }
7287
7288         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7289         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7290
7291         ins_flag = 0;
7292         start_new_bblock = 0;
7293         cfg->cbb = bblock;
7294         while (ip < end) {
7295                 if (cfg->method == method)
7296                         cfg->real_offset = ip - header->code;
7297                 else
7298                         cfg->real_offset = inline_offset;
7299                 cfg->ip = ip;
7300
7301                 context_used = 0;
7302                 
7303                 if (start_new_bblock) {
7304                         bblock->cil_length = ip - bblock->cil_code;
7305                         if (start_new_bblock == 2) {
7306                                 g_assert (ip == tblock->cil_code);
7307                         } else {
7308                                 GET_BBLOCK (cfg, tblock, ip);
7309                         }
7310                         bblock->next_bb = tblock;
7311                         bblock = tblock;
7312                         cfg->cbb = bblock;
7313                         start_new_bblock = 0;
7314                         for (i = 0; i < bblock->in_scount; ++i) {
7315                                 if (cfg->verbose_level > 3)
7316                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7317                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7318                                 *sp++ = ins;
7319                         }
7320                         if (class_inits)
7321                                 g_slist_free (class_inits);
7322                         class_inits = NULL;
7323                 } else {
7324                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7325                                 link_bblock (cfg, bblock, tblock);
7326                                 if (sp != stack_start) {
7327                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7328                                         sp = stack_start;
7329                                         CHECK_UNVERIFIABLE (cfg);
7330                                 }
7331                                 bblock->next_bb = tblock;
7332                                 bblock = tblock;
7333                                 cfg->cbb = bblock;
7334                                 for (i = 0; i < bblock->in_scount; ++i) {
7335                                         if (cfg->verbose_level > 3)
7336                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7337                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7338                                         *sp++ = ins;
7339                                 }
7340                                 g_slist_free (class_inits);
7341                                 class_inits = NULL;
7342                         }
7343                 }
7344
7345                 if (skip_dead_blocks) {
7346                         int ip_offset = ip - header->code;
7347
7348                         if (ip_offset == bb->end)
7349                                 bb = bb->next;
7350
7351                         if (bb->dead) {
7352                                 int op_size = mono_opcode_size (ip, end);
7353                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7354
7355                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7356
7357                                 if (ip_offset + op_size == bb->end) {
7358                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7359                                         MONO_ADD_INS (bblock, ins);
7360                                         start_new_bblock = 1;
7361                                 }
7362
7363                                 ip += op_size;
7364                                 continue;
7365                         }
7366                 }
7367                 /*
7368                  * Sequence points are points where the debugger can place a breakpoint.
7369                  * Currently, we generate these automatically at points where the IL
7370                  * stack is empty.
7371                  */
7372                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7373                         /*
7374                          * Make methods interruptable at the beginning, and at the targets of
7375                          * backward branches.
7376                          * Also, do this at the start of every bblock in methods with clauses too,
7377                          * to be able to handle instructions with inprecise control flow like
7378                          * throw/endfinally.
7379                          * Backward branches are handled at the end of method-to-ir ().
7380                          */
7381                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7382
7383                         /* Avoid sequence points on empty IL like .volatile */
7384                         // FIXME: Enable this
7385                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7386                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7387                         if (sp != stack_start)
7388                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7389                         MONO_ADD_INS (cfg->cbb, ins);
7390
7391                         if (sym_seq_points)
7392                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7393                 }
7394
7395                 bblock->real_offset = cfg->real_offset;
7396
7397                 if ((cfg->method == method) && cfg->coverage_info) {
7398                         guint32 cil_offset = ip - header->code;
7399                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7400
7401                         /* TODO: Use an increment here */
7402 #if defined(TARGET_X86)
7403                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7404                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7405                         ins->inst_imm = 1;
7406                         MONO_ADD_INS (cfg->cbb, ins);
7407 #else
7408                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7409                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7410 #endif
7411                 }
7412
7413                 if (cfg->verbose_level > 3)
7414                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7415
7416                 switch (*ip) {
7417                 case CEE_NOP:
7418                         if (seq_points && !sym_seq_points && sp != stack_start) {
7419                                 /*
7420                                  * The C# compiler uses these nops to notify the JIT that it should
7421                                  * insert seq points.
7422                                  */
7423                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7424                                 MONO_ADD_INS (cfg->cbb, ins);
7425                         }
7426                         if (cfg->keep_cil_nops)
7427                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7428                         else
7429                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7430                         ip++;
7431                         MONO_ADD_INS (bblock, ins);
7432                         break;
7433                 case CEE_BREAK:
7434                         if (should_insert_brekpoint (cfg->method)) {
7435                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7436                         } else {
7437                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7438                         }
7439                         ip++;
7440                         MONO_ADD_INS (bblock, ins);
7441                         break;
7442                 case CEE_LDARG_0:
7443                 case CEE_LDARG_1:
7444                 case CEE_LDARG_2:
7445                 case CEE_LDARG_3:
7446                         CHECK_STACK_OVF (1);
7447                         n = (*ip)-CEE_LDARG_0;
7448                         CHECK_ARG (n);
7449                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7450                         ip++;
7451                         *sp++ = ins;
7452                         break;
7453                 case CEE_LDLOC_0:
7454                 case CEE_LDLOC_1:
7455                 case CEE_LDLOC_2:
7456                 case CEE_LDLOC_3:
7457                         CHECK_STACK_OVF (1);
7458                         n = (*ip)-CEE_LDLOC_0;
7459                         CHECK_LOCAL (n);
7460                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7461                         ip++;
7462                         *sp++ = ins;
7463                         break;
7464                 case CEE_STLOC_0:
7465                 case CEE_STLOC_1:
7466                 case CEE_STLOC_2:
7467                 case CEE_STLOC_3: {
7468                         CHECK_STACK (1);
7469                         n = (*ip)-CEE_STLOC_0;
7470                         CHECK_LOCAL (n);
7471                         --sp;
7472                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7473                                 UNVERIFIED;
7474                         emit_stloc_ir (cfg, sp, header, n);
7475                         ++ip;
7476                         inline_costs += 1;
7477                         break;
7478                         }
7479                 case CEE_LDARG_S:
7480                         CHECK_OPSIZE (2);
7481                         CHECK_STACK_OVF (1);
7482                         n = ip [1];
7483                         CHECK_ARG (n);
7484                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7485                         *sp++ = ins;
7486                         ip += 2;
7487                         break;
7488                 case CEE_LDARGA_S:
7489                         CHECK_OPSIZE (2);
7490                         CHECK_STACK_OVF (1);
7491                         n = ip [1];
7492                         CHECK_ARG (n);
7493                         NEW_ARGLOADA (cfg, ins, n);
7494                         MONO_ADD_INS (cfg->cbb, ins);
7495                         *sp++ = ins;
7496                         ip += 2;
7497                         break;
7498                 case CEE_STARG_S:
7499                         CHECK_OPSIZE (2);
7500                         CHECK_STACK (1);
7501                         --sp;
7502                         n = ip [1];
7503                         CHECK_ARG (n);
7504                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7505                                 UNVERIFIED;
7506                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7507                         ip += 2;
7508                         break;
7509                 case CEE_LDLOC_S:
7510                         CHECK_OPSIZE (2);
7511                         CHECK_STACK_OVF (1);
7512                         n = ip [1];
7513                         CHECK_LOCAL (n);
7514                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7515                         *sp++ = ins;
7516                         ip += 2;
7517                         break;
7518                 case CEE_LDLOCA_S: {
7519                         unsigned char *tmp_ip;
7520                         CHECK_OPSIZE (2);
7521                         CHECK_STACK_OVF (1);
7522                         CHECK_LOCAL (ip [1]);
7523
7524                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7525                                 ip = tmp_ip;
7526                                 inline_costs += 1;
7527                                 break;
7528                         }
7529
7530                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7531                         *sp++ = ins;
7532                         ip += 2;
7533                         break;
7534                 }
7535                 case CEE_STLOC_S:
7536                         CHECK_OPSIZE (2);
7537                         CHECK_STACK (1);
7538                         --sp;
7539                         CHECK_LOCAL (ip [1]);
7540                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7541                                 UNVERIFIED;
7542                         emit_stloc_ir (cfg, sp, header, ip [1]);
7543                         ip += 2;
7544                         inline_costs += 1;
7545                         break;
7546                 case CEE_LDNULL:
7547                         CHECK_STACK_OVF (1);
7548                         EMIT_NEW_PCONST (cfg, ins, NULL);
7549                         ins->type = STACK_OBJ;
7550                         ++ip;
7551                         *sp++ = ins;
7552                         break;
7553                 case CEE_LDC_I4_M1:
7554                         CHECK_STACK_OVF (1);
7555                         EMIT_NEW_ICONST (cfg, ins, -1);
7556                         ++ip;
7557                         *sp++ = ins;
7558                         break;
7559                 case CEE_LDC_I4_0:
7560                 case CEE_LDC_I4_1:
7561                 case CEE_LDC_I4_2:
7562                 case CEE_LDC_I4_3:
7563                 case CEE_LDC_I4_4:
7564                 case CEE_LDC_I4_5:
7565                 case CEE_LDC_I4_6:
7566                 case CEE_LDC_I4_7:
7567                 case CEE_LDC_I4_8:
7568                         CHECK_STACK_OVF (1);
7569                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7570                         ++ip;
7571                         *sp++ = ins;
7572                         break;
7573                 case CEE_LDC_I4_S:
7574                         CHECK_OPSIZE (2);
7575                         CHECK_STACK_OVF (1);
7576                         ++ip;
7577                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7578                         ++ip;
7579                         *sp++ = ins;
7580                         break;
7581                 case CEE_LDC_I4:
7582                         CHECK_OPSIZE (5);
7583                         CHECK_STACK_OVF (1);
7584                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7585                         ip += 5;
7586                         *sp++ = ins;
7587                         break;
7588                 case CEE_LDC_I8:
7589                         CHECK_OPSIZE (9);
7590                         CHECK_STACK_OVF (1);
7591                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7592                         ins->type = STACK_I8;
7593                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7594                         ++ip;
7595                         ins->inst_l = (gint64)read64 (ip);
7596                         MONO_ADD_INS (bblock, ins);
7597                         ip += 8;
7598                         *sp++ = ins;
7599                         break;
7600                 case CEE_LDC_R4: {
7601                         float *f;
7602                         gboolean use_aotconst = FALSE;
7603
7604 #ifdef TARGET_POWERPC
7605                         /* FIXME: Clean this up */
7606                         if (cfg->compile_aot)
7607                                 use_aotconst = TRUE;
7608 #endif
7609
7610                         /* FIXME: we should really allocate this only late in the compilation process */
7611                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7612                         CHECK_OPSIZE (5);
7613                         CHECK_STACK_OVF (1);
7614
7615                         if (use_aotconst) {
7616                                 MonoInst *cons;
7617                                 int dreg;
7618
7619                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7620
7621                                 dreg = alloc_freg (cfg);
7622                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7623                                 ins->type = STACK_R8;
7624                         } else {
7625                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7626                                 ins->type = STACK_R8;
7627                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7628                                 ins->inst_p0 = f;
7629                                 MONO_ADD_INS (bblock, ins);
7630                         }
7631                         ++ip;
7632                         readr4 (ip, f);
7633                         ip += 4;
7634                         *sp++ = ins;                    
7635                         break;
7636                 }
7637                 case CEE_LDC_R8: {
7638                         double *d;
7639                         gboolean use_aotconst = FALSE;
7640
7641 #ifdef TARGET_POWERPC
7642                         /* FIXME: Clean this up */
7643                         if (cfg->compile_aot)
7644                                 use_aotconst = TRUE;
7645 #endif
7646
7647                         /* FIXME: we should really allocate this only late in the compilation process */
7648                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7649                         CHECK_OPSIZE (9);
7650                         CHECK_STACK_OVF (1);
7651
7652                         if (use_aotconst) {
7653                                 MonoInst *cons;
7654                                 int dreg;
7655
7656                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7657
7658                                 dreg = alloc_freg (cfg);
7659                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7660                                 ins->type = STACK_R8;
7661                         } else {
7662                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7663                                 ins->type = STACK_R8;
7664                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7665                                 ins->inst_p0 = d;
7666                                 MONO_ADD_INS (bblock, ins);
7667                         }
7668                         ++ip;
7669                         readr8 (ip, d);
7670                         ip += 8;
7671                         *sp++ = ins;
7672                         break;
7673                 }
7674                 case CEE_DUP: {
7675                         MonoInst *temp, *store;
7676                         CHECK_STACK (1);
7677                         CHECK_STACK_OVF (1);
7678                         sp--;
7679                         ins = *sp;
7680
7681                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7682                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7683
7684                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7685                         *sp++ = ins;
7686
7687                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7688                         *sp++ = ins;
7689
7690                         ++ip;
7691                         inline_costs += 2;
7692                         break;
7693                 }
7694                 case CEE_POP:
7695                         CHECK_STACK (1);
7696                         ip++;
7697                         --sp;
7698
7699 #ifdef TARGET_X86
7700                         if (sp [0]->type == STACK_R8)
7701                                 /* we need to pop the value from the x86 FP stack */
7702                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7703 #endif
7704                         break;
7705                 case CEE_JMP: {
7706                         MonoCallInst *call;
7707
7708                         INLINE_FAILURE ("jmp");
7709                         GSHAREDVT_FAILURE (*ip);
7710
7711                         CHECK_OPSIZE (5);
7712                         if (stack_start != sp)
7713                                 UNVERIFIED;
7714                         token = read32 (ip + 1);
7715                         /* FIXME: check the signature matches */
7716                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7717
7718                         if (!cmethod || mono_loader_get_last_error ())
7719                                 LOAD_ERROR;
7720  
7721                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7722                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7723
7724                         if (mono_security_cas_enabled ())
7725                                 CHECK_CFG_EXCEPTION;
7726
7727                         if (ARCH_HAVE_OP_TAIL_CALL) {
7728                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7729                                 int i, n;
7730
7731                                 /* Handle tail calls similarly to calls */
7732                                 n = fsig->param_count + fsig->hasthis;
7733
7734                                 DISABLE_AOT (cfg);
7735
7736                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7737                                 call->method = cmethod;
7738                                 call->tail_call = TRUE;
7739                                 call->signature = mono_method_signature (cmethod);
7740                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7741                                 call->inst.inst_p0 = cmethod;
7742                                 for (i = 0; i < n; ++i)
7743                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7744
7745                                 mono_arch_emit_call (cfg, call);
7746                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7747                         } else {
7748                                 for (i = 0; i < num_args; ++i)
7749                                         /* Prevent arguments from being optimized away */
7750                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7751
7752                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7753                                 ins = (MonoInst*)call;
7754                                 ins->inst_p0 = cmethod;
7755                                 MONO_ADD_INS (bblock, ins);
7756                         }
7757
7758                         ip += 5;
7759                         start_new_bblock = 1;
7760                         break;
7761                 }
7762                 case CEE_CALLI:
7763                 case CEE_CALL:
7764                 case CEE_CALLVIRT: {
7765                         MonoInst *addr = NULL;
7766                         MonoMethodSignature *fsig = NULL;
7767                         int array_rank = 0;
7768                         int virtual = *ip == CEE_CALLVIRT;
7769                         int calli = *ip == CEE_CALLI;
7770                         gboolean pass_imt_from_rgctx = FALSE;
7771                         MonoInst *imt_arg = NULL;
7772                         MonoInst *keep_this_alive = NULL;
7773                         gboolean pass_vtable = FALSE;
7774                         gboolean pass_mrgctx = FALSE;
7775                         MonoInst *vtable_arg = NULL;
7776                         gboolean check_this = FALSE;
7777                         gboolean supported_tail_call = FALSE;
7778                         gboolean tail_call = FALSE;
7779                         gboolean need_seq_point = FALSE;
7780                         guint32 call_opcode = *ip;
7781                         gboolean emit_widen = TRUE;
7782                         gboolean push_res = TRUE;
7783                         gboolean skip_ret = FALSE;
7784                         gboolean delegate_invoke = FALSE;
7785
7786                         CHECK_OPSIZE (5);
7787                         token = read32 (ip + 1);
7788
7789                         ins = NULL;
7790
7791                         if (calli) {
7792                                 //GSHAREDVT_FAILURE (*ip);
7793                                 cmethod = NULL;
7794                                 CHECK_STACK (1);
7795                                 --sp;
7796                                 addr = *sp;
7797                                 fsig = mini_get_signature (method, token, generic_context);
7798                                 n = fsig->param_count + fsig->hasthis;
7799
7800                                 if (method->dynamic && fsig->pinvoke) {
7801                                         MonoInst *args [3];
7802
7803                                         /*
7804                                          * This is a call through a function pointer using a pinvoke
7805                                          * signature. Have to create a wrapper and call that instead.
7806                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7807                                          * instead based on the signature.
7808                                          */
7809                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7810                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7811                                         args [2] = addr;
7812                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7813                                 }
7814                         } else {
7815                                 MonoMethod *cil_method;
7816
7817                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7818                                 cil_method = cmethod;
7819                                 
7820                                 if (constrained_call) {
7821                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7822                                                 if (cfg->verbose_level > 2)
7823                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7824                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7825                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7826                                                           cfg->generic_sharing_context)) {
7827                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7828                                                 }
7829                                         } else {
7830                                                 if (cfg->verbose_level > 2)
7831                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7832
7833                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7834                                                         /* 
7835                                                          * This is needed since get_method_constrained can't find 
7836                                                          * the method in klass representing a type var.
7837                                                          * The type var is guaranteed to be a reference type in this
7838                                                          * case.
7839                                                          */
7840                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7841                                                                 g_assert (!cmethod->klass->valuetype);
7842                                                 } else {
7843                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7844                                                 }
7845                                         }
7846                                 }
7847                                         
7848                                 if (!cmethod || mono_loader_get_last_error ())
7849                                         LOAD_ERROR;
7850                                 if (!dont_verify && !cfg->skip_visibility) {
7851                                         MonoMethod *target_method = cil_method;
7852                                         if (method->is_inflated) {
7853                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7854                                         }
7855                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7856                                                 !mono_method_can_access_method (method, cil_method))
7857                                                 METHOD_ACCESS_FAILURE;
7858                                 }
7859
7860                                 if (mono_security_core_clr_enabled ())
7861                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7862
7863                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7864                                         /* MS.NET seems to silently convert this to a callvirt */
7865                                         virtual = 1;
7866
7867                                 {
7868                                         /*
7869                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7870                                          * converts to a callvirt.
7871                                          *
7872                                          * tests/bug-515884.il is an example of this behavior
7873                                          */
7874                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7875                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7876                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7877                                                 virtual = 1;
7878                                 }
7879
7880                                 if (!cmethod->klass->inited)
7881                                         if (!mono_class_init (cmethod->klass))
7882                                                 TYPE_LOAD_ERROR (cmethod->klass);
7883
7884                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7885                                     mini_class_is_system_array (cmethod->klass)) {
7886                                         array_rank = cmethod->klass->rank;
7887                                         fsig = mono_method_signature (cmethod);
7888                                 } else {
7889                                         fsig = mono_method_signature (cmethod);
7890
7891                                         if (!fsig)
7892                                                 LOAD_ERROR;
7893
7894                                         if (fsig->pinvoke) {
7895                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7896                                                         check_for_pending_exc, cfg->compile_aot);
7897                                                 fsig = mono_method_signature (wrapper);
7898                                         } else if (constrained_call) {
7899                                                 fsig = mono_method_signature (cmethod);
7900                                         } else {
7901                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7902                                         }
7903                                 }
7904
7905                                 mono_save_token_info (cfg, image, token, cil_method);
7906
7907                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7908                                         /*
7909                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7910                                          * foo (bar (), baz ())
7911                                          * works correctly. MS does this also:
7912                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7913                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7914                                          * even for simple cases, like:
7915                                          * int i = foo ();
7916                                          */
7917                                         /* Special case a few common successor opcodes */
7918                                         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)))
7919                                                 need_seq_point = TRUE;
7920                                 }
7921
7922                                 n = fsig->param_count + fsig->hasthis;
7923
7924                                 /* Don't support calls made using type arguments for now */
7925                                 /*
7926                                 if (cfg->gsharedvt) {
7927                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7928                                                 GSHAREDVT_FAILURE (*ip);
7929                                 }
7930                                 */
7931
7932                                 if (mono_security_cas_enabled ()) {
7933                                         if (check_linkdemand (cfg, method, cmethod))
7934                                                 INLINE_FAILURE ("linkdemand");
7935                                         CHECK_CFG_EXCEPTION;
7936                                 }
7937
7938                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7939                                         g_assert_not_reached ();
7940                         }
7941
7942                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7943                                 UNVERIFIED;
7944
7945                         if (!cfg->generic_sharing_context && cmethod)
7946                                 g_assert (!mono_method_check_context_used (cmethod));
7947
7948                         CHECK_STACK (n);
7949
7950                         //g_assert (!virtual || fsig->hasthis);
7951
7952                         sp -= n;
7953
7954                         if (constrained_call) {
7955                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7956                                         /*
7957                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7958                                          */
7959                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7960                                                 /* The 'Own method' case below */
7961                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7962                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7963                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7964                                                            (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)) &&
7965                                                            (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]))))) {
7966                                                 MonoInst *args [16];
7967
7968                                                 /*
7969                                                  * This case handles calls to
7970                                                  * - object:ToString()/Equals()/GetHashCode(),
7971                                                  * - System.IComparable<T>:CompareTo()
7972                                                  * - System.IEquatable<T>:Equals ()
7973                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7974                                                  */
7975
7976                                                 args [0] = sp [0];
7977                                                 if (mono_method_check_context_used (cmethod))
7978                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7979                                                 else
7980                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7981                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7982
7983                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7984                                                 if (fsig->hasthis && fsig->param_count) {
7985                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7986                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7987                                                         ins->dreg = alloc_preg (cfg);
7988                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7989                                                         MONO_ADD_INS (cfg->cbb, ins);
7990                                                         args [4] = ins;
7991
7992                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7993                                                                 int addr_reg;
7994
7995                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
7996
7997                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
7998                                                                 addr_reg = ins->dreg;
7999                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8000                                                         } else {
8001                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8002                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8003                                                         }
8004                                                 } else {
8005                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8006                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8007                                                 }
8008                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8009                                                 emit_widen = FALSE;
8010
8011                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8012                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8013                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
8014                                                         MonoInst *add;
8015
8016                                                         /* Unbox */
8017                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8018                                                         MONO_ADD_INS (cfg->cbb, add);
8019                                                         /* Load value */
8020                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8021                                                         MONO_ADD_INS (cfg->cbb, ins);
8022                                                         /* ins represents the call result */
8023                                                 }
8024
8025                                                 goto call_end;
8026                                         } else {
8027                                                 GSHAREDVT_FAILURE (*ip);
8028                                         }
8029                                 }
8030                                 /*
8031                                  * We have the `constrained.' prefix opcode.
8032                                  */
8033                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8034                                         /*
8035                                          * The type parameter is instantiated as a valuetype,
8036                                          * but that type doesn't override the method we're
8037                                          * calling, so we need to box `this'.
8038                                          */
8039                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8040                                         ins->klass = constrained_call;
8041                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8042                                         CHECK_CFG_EXCEPTION;
8043                                 } else if (!constrained_call->valuetype) {
8044                                         int dreg = alloc_ireg_ref (cfg);
8045
8046                                         /*
8047                                          * The type parameter is instantiated as a reference
8048                                          * type.  We have a managed pointer on the stack, so
8049                                          * we need to dereference it here.
8050                                          */
8051                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8052                                         ins->type = STACK_OBJ;
8053                                         sp [0] = ins;
8054                                 } else {
8055                                         if (cmethod->klass->valuetype) {
8056                                                 /* Own method */
8057                                         } else {
8058                                                 /* Interface method */
8059                                                 int ioffset, slot;
8060
8061                                                 mono_class_setup_vtable (constrained_call);
8062                                                 CHECK_TYPELOAD (constrained_call);
8063                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8064                                                 if (ioffset == -1)
8065                                                         TYPE_LOAD_ERROR (constrained_call);
8066                                                 slot = mono_method_get_vtable_slot (cmethod);
8067                                                 if (slot == -1)
8068                                                         TYPE_LOAD_ERROR (cmethod->klass);
8069                                                 cmethod = constrained_call->vtable [ioffset + slot];
8070
8071                                                 if (cmethod->klass == mono_defaults.enum_class) {
8072                                                         /* Enum implements some interfaces, so treat this as the first case */
8073                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8074                                                         ins->klass = constrained_call;
8075                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8076                                                         CHECK_CFG_EXCEPTION;
8077                                                 }
8078                                         }
8079                                         virtual = 0;
8080                                 }
8081                                 constrained_call = NULL;
8082                         }
8083
8084                         if (!calli && check_call_signature (cfg, fsig, sp))
8085                                 UNVERIFIED;
8086
8087 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8088                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8089                                 delegate_invoke = TRUE;
8090 #endif
8091
8092                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8093                                 bblock = cfg->cbb;
8094                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8095                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8096                                         emit_widen = FALSE;
8097                                 }
8098
8099                                 goto call_end;
8100                         }
8101
8102                         /* 
8103                          * If the callee is a shared method, then its static cctor
8104                          * might not get called after the call was patched.
8105                          */
8106                         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)) {
8107                                 emit_generic_class_init (cfg, cmethod->klass);
8108                                 CHECK_TYPELOAD (cmethod->klass);
8109                         }
8110
8111                         if (cmethod)
8112                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8113
8114                         if (cfg->generic_sharing_context && cmethod) {
8115                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8116
8117                                 context_used = mini_method_check_context_used (cfg, cmethod);
8118
8119                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8120                                         /* Generic method interface
8121                                            calls are resolved via a
8122                                            helper function and don't
8123                                            need an imt. */
8124                                         if (!cmethod_context || !cmethod_context->method_inst)
8125                                                 pass_imt_from_rgctx = TRUE;
8126                                 }
8127
8128                                 /*
8129                                  * If a shared method calls another
8130                                  * shared method then the caller must
8131                                  * have a generic sharing context
8132                                  * because the magic trampoline
8133                                  * requires it.  FIXME: We shouldn't
8134                                  * have to force the vtable/mrgctx
8135                                  * variable here.  Instead there
8136                                  * should be a flag in the cfg to
8137                                  * request a generic sharing context.
8138                                  */
8139                                 if (context_used &&
8140                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8141                                         mono_get_vtable_var (cfg);
8142                         }
8143
8144                         if (pass_vtable) {
8145                                 if (context_used) {
8146                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8147                                 } else {
8148                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8149
8150                                         CHECK_TYPELOAD (cmethod->klass);
8151                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8152                                 }
8153                         }
8154
8155                         if (pass_mrgctx) {
8156                                 g_assert (!vtable_arg);
8157
8158                                 if (!cfg->compile_aot) {
8159                                         /* 
8160                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8161                                          * for type load errors before.
8162                                          */
8163                                         mono_class_setup_vtable (cmethod->klass);
8164                                         CHECK_TYPELOAD (cmethod->klass);
8165                                 }
8166
8167                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8168
8169                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8170                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8171                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8172                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8173                                         if (virtual)
8174                                                 check_this = TRUE;
8175                                         virtual = 0;
8176                                 }
8177                         }
8178
8179                         if (pass_imt_from_rgctx) {
8180                                 g_assert (!pass_vtable);
8181                                 g_assert (cmethod);
8182
8183                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8184                                         cmethod, MONO_RGCTX_INFO_METHOD);
8185                         }
8186
8187                         if (check_this)
8188                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8189
8190                         /* Calling virtual generic methods */
8191                         if (cmethod && virtual && 
8192                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8193                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8194                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8195                             fsig->generic_param_count && 
8196                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8197                                 MonoInst *this_temp, *this_arg_temp, *store;
8198                                 MonoInst *iargs [4];
8199                                 gboolean use_imt = FALSE;
8200
8201                                 g_assert (fsig->is_inflated);
8202
8203                                 /* Prevent inlining of methods that contain indirect calls */
8204                                 INLINE_FAILURE ("virtual generic call");
8205
8206                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8207                                         GSHAREDVT_FAILURE (*ip);
8208
8209 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8210                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8211                                         use_imt = TRUE;
8212 #endif
8213
8214                                 if (use_imt) {
8215                                         g_assert (!imt_arg);
8216                                         if (!context_used)
8217                                                 g_assert (cmethod->is_inflated);
8218                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8219                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8220                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8221                                 } else {
8222                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8223                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8224                                         MONO_ADD_INS (bblock, store);
8225
8226                                         /* FIXME: This should be a managed pointer */
8227                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8228
8229                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8230                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8231                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8232                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8233                                         addr = mono_emit_jit_icall (cfg,
8234                                                                                                 mono_helper_compile_generic_method, iargs);
8235
8236                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8237
8238                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8239                                 }
8240
8241                                 goto call_end;
8242                         }
8243
8244                         /*
8245                          * Implement a workaround for the inherent races involved in locking:
8246                          * Monitor.Enter ()
8247                          * try {
8248                          * } finally {
8249                          *    Monitor.Exit ()
8250                          * }
8251                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8252                          * try block, the Exit () won't be executed, see:
8253                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8254                          * To work around this, we extend such try blocks to include the last x bytes
8255                          * of the Monitor.Enter () call.
8256                          */
8257                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8258                                 MonoBasicBlock *tbb;
8259
8260                                 GET_BBLOCK (cfg, tbb, ip + 5);
8261                                 /* 
8262                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8263                                  * from Monitor.Enter like ArgumentNullException.
8264                                  */
8265                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8266                                         /* Mark this bblock as needing to be extended */
8267                                         tbb->extend_try_block = TRUE;
8268                                 }
8269                         }
8270
8271                         /* Conversion to a JIT intrinsic */
8272                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8273                                 bblock = cfg->cbb;
8274                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8275                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8276                                         emit_widen = FALSE;
8277                                 }
8278                                 goto call_end;
8279                         }
8280
8281                         /* Inlining */
8282                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8283                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8284                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8285                                  !g_list_find (dont_inline, cmethod)) {
8286                                 int costs;
8287                                 gboolean always = FALSE;
8288
8289                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8290                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8291                                         /* Prevent inlining of methods that call wrappers */
8292                                         INLINE_FAILURE ("wrapper call");
8293                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8294                                         always = TRUE;
8295                                 }
8296
8297                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8298                                 if (costs) {
8299                                         cfg->real_offset += 5;
8300                                         bblock = cfg->cbb;
8301
8302                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8303                                                 /* *sp is already set by inline_method */
8304                                                 sp++;
8305                                                 push_res = FALSE;
8306                                         }
8307
8308                                         inline_costs += costs;
8309
8310                                         goto call_end;
8311                                 }
8312                         }
8313
8314                         /* Tail recursion elimination */
8315                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8316                                 gboolean has_vtargs = FALSE;
8317                                 int i;
8318
8319                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8320                                 INLINE_FAILURE ("tail call");
8321
8322                                 /* keep it simple */
8323                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8324                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8325                                                 has_vtargs = TRUE;
8326                                 }
8327
8328                                 if (!has_vtargs) {
8329                                         for (i = 0; i < n; ++i)
8330                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8331                                         MONO_INST_NEW (cfg, ins, OP_BR);
8332                                         MONO_ADD_INS (bblock, ins);
8333                                         tblock = start_bblock->out_bb [0];
8334                                         link_bblock (cfg, bblock, tblock);
8335                                         ins->inst_target_bb = tblock;
8336                                         start_new_bblock = 1;
8337
8338                                         /* skip the CEE_RET, too */
8339                                         if (ip_in_bb (cfg, bblock, ip + 5))
8340                                                 skip_ret = TRUE;
8341                                         push_res = FALSE;
8342                                         goto call_end;
8343                                 }
8344                         }
8345
8346                         inline_costs += 10 * num_calls++;
8347
8348                         /*
8349                          * Making generic calls out of gsharedvt methods.
8350                          */
8351                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8352                                 MonoRgctxInfoType info_type;
8353
8354                                 if (virtual) {
8355                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8356                                                 //GSHAREDVT_FAILURE (*ip);
8357                                         // disable for possible remoting calls
8358                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8359                                                 GSHAREDVT_FAILURE (*ip);
8360                                         if (fsig->generic_param_count) {
8361                                                 /* virtual generic call */
8362                                                 g_assert (mono_use_imt);
8363                                                 g_assert (!imt_arg);
8364                                                 /* Same as the virtual generic case above */
8365                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8366                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8367                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8368                                                 vtable_arg = NULL;
8369                                         }
8370                                 }
8371
8372                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8373                                         /* test_0_multi_dim_arrays () in gshared.cs */
8374                                         GSHAREDVT_FAILURE (*ip);
8375
8376                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8377                                         keep_this_alive = sp [0];
8378
8379                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8380                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8381                                 else
8382                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8383                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8384
8385                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8386                                 goto call_end;
8387                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8388                                 /*
8389                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8390                                  */
8391                                 MonoInst *callee = addr;
8392
8393                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8394                                         /* Not tested */
8395                                         GSHAREDVT_FAILURE (*ip);
8396
8397                                 addr = emit_get_rgctx_sig (cfg, context_used,
8398                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8399                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8400                                 goto call_end;
8401                         }
8402
8403                         /* Generic sharing */
8404                         /* FIXME: only do this for generic methods if
8405                            they are not shared! */
8406                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8407                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8408                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8409                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8410                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8411                                 INLINE_FAILURE ("gshared");
8412
8413                                 g_assert (cfg->generic_sharing_context && cmethod);
8414                                 g_assert (!addr);
8415
8416                                 /*
8417                                  * We are compiling a call to a
8418                                  * generic method from shared code,
8419                                  * which means that we have to look up
8420                                  * the method in the rgctx and do an
8421                                  * indirect call.
8422                                  */
8423                                 if (fsig->hasthis)
8424                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8425
8426                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8427                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8428                                 goto call_end;
8429                         }
8430
8431                         /* Indirect calls */
8432                         if (addr) {
8433                                 if (call_opcode == CEE_CALL)
8434                                         g_assert (context_used);
8435                                 else if (call_opcode == CEE_CALLI)
8436                                         g_assert (!vtable_arg);
8437                                 else
8438                                         /* FIXME: what the hell is this??? */
8439                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8440                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8441
8442                                 /* Prevent inlining of methods with indirect calls */
8443                                 INLINE_FAILURE ("indirect call");
8444
8445                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8446                                         int info_type;
8447                                         gpointer info_data;
8448
8449                                         /* 
8450                                          * Instead of emitting an indirect call, emit a direct call
8451                                          * with the contents of the aotconst as the patch info.
8452                                          */
8453                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8454                                                 info_type = addr->inst_c1;
8455                                                 info_data = addr->inst_p0;
8456                                         } else {
8457                                                 info_type = addr->inst_right->inst_c1;
8458                                                 info_data = addr->inst_right->inst_left;
8459                                         }
8460                                         
8461                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8462                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8463                                                 NULLIFY_INS (addr);
8464                                                 goto call_end;
8465                                         }
8466                                 }
8467                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8468                                 goto call_end;
8469                         }
8470                                         
8471                         /* Array methods */
8472                         if (array_rank) {
8473                                 MonoInst *addr;
8474
8475                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8476                                         MonoInst *val = sp [fsig->param_count];
8477
8478                                         if (val->type == STACK_OBJ) {
8479                                                 MonoInst *iargs [2];
8480
8481                                                 iargs [0] = sp [0];
8482                                                 iargs [1] = val;
8483                                                 
8484                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8485                                         }
8486                                         
8487                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8488                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8489                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8490                                                 emit_write_barrier (cfg, addr, val);
8491                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8492                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8493
8494                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8495                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8496                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8497                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8498                                         CHECK_TYPELOAD (cmethod->klass);
8499                                         
8500                                         readonly = FALSE;
8501                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8502                                         ins = addr;
8503                                 } else {
8504                                         g_assert_not_reached ();
8505                                 }
8506
8507                                 emit_widen = FALSE;
8508                                 goto call_end;
8509                         }
8510
8511                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8512                         if (ins)
8513                                 goto call_end;
8514
8515                         /* Tail prefix / tail call optimization */
8516
8517                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8518                         /* FIXME: runtime generic context pointer for jumps? */
8519                         /* FIXME: handle this for generic sharing eventually */
8520                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8521                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8522                                 supported_tail_call = TRUE;
8523
8524                         if (supported_tail_call) {
8525                                 MonoCallInst *call;
8526
8527                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8528                                 INLINE_FAILURE ("tail call");
8529
8530                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8531
8532                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8533                                         /* Handle tail calls similarly to normal calls */
8534                                         tail_call = TRUE;
8535                                 } else {
8536                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8537                                         call->tail_call = TRUE;
8538                                         call->method = cmethod;
8539                                         call->signature = mono_method_signature (cmethod);
8540
8541                                         /*
8542                                          * We implement tail calls by storing the actual arguments into the 
8543                                          * argument variables, then emitting a CEE_JMP.
8544                                          */
8545                                         for (i = 0; i < n; ++i) {
8546                                                 /* Prevent argument from being register allocated */
8547                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8548                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8549                                         }
8550                                         ins = (MonoInst*)call;
8551                                         ins->inst_p0 = cmethod;
8552                                         ins->inst_p1 = arg_array [0];
8553                                         MONO_ADD_INS (bblock, ins);
8554                                         link_bblock (cfg, bblock, end_bblock);                  
8555                                         start_new_bblock = 1;
8556
8557                                         // FIXME: Eliminate unreachable epilogs
8558
8559                                         /*
8560                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8561                                          * only reachable from this call.
8562                                          */
8563                                         GET_BBLOCK (cfg, tblock, ip + 5);
8564                                         if (tblock == bblock || tblock->in_count == 0)
8565                                                 skip_ret = TRUE;
8566                                         push_res = FALSE;
8567
8568                                         goto call_end;
8569                                 }
8570                         }
8571
8572                         /* 
8573                          * Synchronized wrappers.
8574                          * Its hard to determine where to replace a method with its synchronized
8575                          * wrapper without causing an infinite recursion. The current solution is
8576                          * to add the synchronized wrapper in the trampolines, and to
8577                          * change the called method to a dummy wrapper, and resolve that wrapper
8578                          * to the real method in mono_jit_compile_method ().
8579                          */
8580                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8581                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8582                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8583                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8584                         }
8585
8586                         /* Common call */
8587                         INLINE_FAILURE ("call");
8588                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8589                                                                                           imt_arg, vtable_arg);
8590
8591                         if (tail_call) {
8592                                 link_bblock (cfg, bblock, end_bblock);                  
8593                                 start_new_bblock = 1;
8594
8595                                 // FIXME: Eliminate unreachable epilogs
8596
8597                                 /*
8598                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8599                                  * only reachable from this call.
8600                                  */
8601                                 GET_BBLOCK (cfg, tblock, ip + 5);
8602                                 if (tblock == bblock || tblock->in_count == 0)
8603                                         skip_ret = TRUE;
8604                                 push_res = FALSE;
8605                         }
8606
8607                         call_end:
8608
8609                         /* End of call, INS should contain the result of the call, if any */
8610
8611                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8612                                 g_assert (ins);
8613                                 if (emit_widen)
8614                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8615                                 else
8616                                         *sp++ = ins;
8617                         }
8618
8619                         if (keep_this_alive) {
8620                                 MonoInst *dummy_use;
8621
8622                                 /* See mono_emit_method_call_full () */
8623                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8624                         }
8625
8626                         CHECK_CFG_EXCEPTION;
8627
8628                         ip += 5;
8629                         if (skip_ret) {
8630                                 g_assert (*ip == CEE_RET);
8631                                 ip += 1;
8632                         }
8633                         ins_flag = 0;
8634                         constrained_call = NULL;
8635                         if (need_seq_point)
8636                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8637                         break;
8638                 }
8639                 case CEE_RET:
8640                         if (cfg->method != method) {
8641                                 /* return from inlined method */
8642                                 /* 
8643                                  * If in_count == 0, that means the ret is unreachable due to
8644                                  * being preceeded by a throw. In that case, inline_method () will
8645                                  * handle setting the return value 
8646                                  * (test case: test_0_inline_throw ()).
8647                                  */
8648                                 if (return_var && cfg->cbb->in_count) {
8649                                         MonoType *ret_type = mono_method_signature (method)->ret;
8650
8651                                         MonoInst *store;
8652                                         CHECK_STACK (1);
8653                                         --sp;
8654
8655                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8656                                                 UNVERIFIED;
8657
8658                                         //g_assert (returnvar != -1);
8659                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8660                                         cfg->ret_var_set = TRUE;
8661                                 } 
8662                         } else {
8663                                 if (cfg->lmf_var && cfg->cbb->in_count)
8664                                         emit_pop_lmf (cfg);
8665
8666                                 if (cfg->ret) {
8667                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8668
8669                                         if (seq_points && !sym_seq_points) {
8670                                                 /* 
8671                                                  * Place a seq point here too even through the IL stack is not
8672                                                  * empty, so a step over on
8673                                                  * call <FOO>
8674                                                  * ret
8675                                                  * will work correctly.
8676                                                  */
8677                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8678                                                 MONO_ADD_INS (cfg->cbb, ins);
8679                                         }
8680
8681                                         g_assert (!return_var);
8682                                         CHECK_STACK (1);
8683                                         --sp;
8684
8685                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8686                                                 UNVERIFIED;
8687
8688                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8689                                                 MonoInst *ret_addr;
8690
8691                                                 if (!cfg->vret_addr) {
8692                                                         MonoInst *ins;
8693
8694                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8695                                                 } else {
8696                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8697
8698                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8699                                                         ins->klass = mono_class_from_mono_type (ret_type);
8700                                                 }
8701                                         } else {
8702 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8703                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8704                                                         MonoInst *iargs [1];
8705                                                         MonoInst *conv;
8706
8707                                                         iargs [0] = *sp;
8708                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8709                                                         mono_arch_emit_setret (cfg, method, conv);
8710                                                 } else {
8711                                                         mono_arch_emit_setret (cfg, method, *sp);
8712                                                 }
8713 #else
8714                                                 mono_arch_emit_setret (cfg, method, *sp);
8715 #endif
8716                                         }
8717                                 }
8718                         }
8719                         if (sp != stack_start)
8720                                 UNVERIFIED;
8721                         MONO_INST_NEW (cfg, ins, OP_BR);
8722                         ip++;
8723                         ins->inst_target_bb = end_bblock;
8724                         MONO_ADD_INS (bblock, ins);
8725                         link_bblock (cfg, bblock, end_bblock);
8726                         start_new_bblock = 1;
8727                         break;
8728                 case CEE_BR_S:
8729                         CHECK_OPSIZE (2);
8730                         MONO_INST_NEW (cfg, ins, OP_BR);
8731                         ip++;
8732                         target = ip + 1 + (signed char)(*ip);
8733                         ++ip;
8734                         GET_BBLOCK (cfg, tblock, target);
8735                         link_bblock (cfg, bblock, tblock);
8736                         ins->inst_target_bb = tblock;
8737                         if (sp != stack_start) {
8738                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8739                                 sp = stack_start;
8740                                 CHECK_UNVERIFIABLE (cfg);
8741                         }
8742                         MONO_ADD_INS (bblock, ins);
8743                         start_new_bblock = 1;
8744                         inline_costs += BRANCH_COST;
8745                         break;
8746                 case CEE_BEQ_S:
8747                 case CEE_BGE_S:
8748                 case CEE_BGT_S:
8749                 case CEE_BLE_S:
8750                 case CEE_BLT_S:
8751                 case CEE_BNE_UN_S:
8752                 case CEE_BGE_UN_S:
8753                 case CEE_BGT_UN_S:
8754                 case CEE_BLE_UN_S:
8755                 case CEE_BLT_UN_S:
8756                         CHECK_OPSIZE (2);
8757                         CHECK_STACK (2);
8758                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8759                         ip++;
8760                         target = ip + 1 + *(signed char*)ip;
8761                         ip++;
8762
8763                         ADD_BINCOND (NULL);
8764
8765                         sp = stack_start;
8766                         inline_costs += BRANCH_COST;
8767                         break;
8768                 case CEE_BR:
8769                         CHECK_OPSIZE (5);
8770                         MONO_INST_NEW (cfg, ins, OP_BR);
8771                         ip++;
8772
8773                         target = ip + 4 + (gint32)read32(ip);
8774                         ip += 4;
8775                         GET_BBLOCK (cfg, tblock, target);
8776                         link_bblock (cfg, bblock, tblock);
8777                         ins->inst_target_bb = tblock;
8778                         if (sp != stack_start) {
8779                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8780                                 sp = stack_start;
8781                                 CHECK_UNVERIFIABLE (cfg);
8782                         }
8783
8784                         MONO_ADD_INS (bblock, ins);
8785
8786                         start_new_bblock = 1;
8787                         inline_costs += BRANCH_COST;
8788                         break;
8789                 case CEE_BRFALSE_S:
8790                 case CEE_BRTRUE_S:
8791                 case CEE_BRFALSE:
8792                 case CEE_BRTRUE: {
8793                         MonoInst *cmp;
8794                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8795                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8796                         guint32 opsize = is_short ? 1 : 4;
8797
8798                         CHECK_OPSIZE (opsize);
8799                         CHECK_STACK (1);
8800                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8801                                 UNVERIFIED;
8802                         ip ++;
8803                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8804                         ip += opsize;
8805
8806                         sp--;
8807
8808                         GET_BBLOCK (cfg, tblock, target);
8809                         link_bblock (cfg, bblock, tblock);
8810                         GET_BBLOCK (cfg, tblock, ip);
8811                         link_bblock (cfg, bblock, tblock);
8812
8813                         if (sp != stack_start) {
8814                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8815                                 CHECK_UNVERIFIABLE (cfg);
8816                         }
8817
8818                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8819                         cmp->sreg1 = sp [0]->dreg;
8820                         type_from_op (cmp, sp [0], NULL);
8821                         CHECK_TYPE (cmp);
8822
8823 #if SIZEOF_REGISTER == 4
8824                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8825                                 /* Convert it to OP_LCOMPARE */
8826                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8827                                 ins->type = STACK_I8;
8828                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8829                                 ins->inst_l = 0;
8830                                 MONO_ADD_INS (bblock, ins);
8831                                 cmp->opcode = OP_LCOMPARE;
8832                                 cmp->sreg2 = ins->dreg;
8833                         }
8834 #endif
8835                         MONO_ADD_INS (bblock, cmp);
8836
8837                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8838                         type_from_op (ins, sp [0], NULL);
8839                         MONO_ADD_INS (bblock, ins);
8840                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8841                         GET_BBLOCK (cfg, tblock, target);
8842                         ins->inst_true_bb = tblock;
8843                         GET_BBLOCK (cfg, tblock, ip);
8844                         ins->inst_false_bb = tblock;
8845                         start_new_bblock = 2;
8846
8847                         sp = stack_start;
8848                         inline_costs += BRANCH_COST;
8849                         break;
8850                 }
8851                 case CEE_BEQ:
8852                 case CEE_BGE:
8853                 case CEE_BGT:
8854                 case CEE_BLE:
8855                 case CEE_BLT:
8856                 case CEE_BNE_UN:
8857                 case CEE_BGE_UN:
8858                 case CEE_BGT_UN:
8859                 case CEE_BLE_UN:
8860                 case CEE_BLT_UN:
8861                         CHECK_OPSIZE (5);
8862                         CHECK_STACK (2);
8863                         MONO_INST_NEW (cfg, ins, *ip);
8864                         ip++;
8865                         target = ip + 4 + (gint32)read32(ip);
8866                         ip += 4;
8867
8868                         ADD_BINCOND (NULL);
8869
8870                         sp = stack_start;
8871                         inline_costs += BRANCH_COST;
8872                         break;
8873                 case CEE_SWITCH: {
8874                         MonoInst *src1;
8875                         MonoBasicBlock **targets;
8876                         MonoBasicBlock *default_bblock;
8877                         MonoJumpInfoBBTable *table;
8878                         int offset_reg = alloc_preg (cfg);
8879                         int target_reg = alloc_preg (cfg);
8880                         int table_reg = alloc_preg (cfg);
8881                         int sum_reg = alloc_preg (cfg);
8882                         gboolean use_op_switch;
8883
8884                         CHECK_OPSIZE (5);
8885                         CHECK_STACK (1);
8886                         n = read32 (ip + 1);
8887                         --sp;
8888                         src1 = sp [0];
8889                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8890                                 UNVERIFIED;
8891
8892                         ip += 5;
8893                         CHECK_OPSIZE (n * sizeof (guint32));
8894                         target = ip + n * sizeof (guint32);
8895
8896                         GET_BBLOCK (cfg, default_bblock, target);
8897                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8898
8899                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8900                         for (i = 0; i < n; ++i) {
8901                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8902                                 targets [i] = tblock;
8903                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8904                                 ip += 4;
8905                         }
8906
8907                         if (sp != stack_start) {
8908                                 /* 
8909                                  * Link the current bb with the targets as well, so handle_stack_args
8910                                  * will set their in_stack correctly.
8911                                  */
8912                                 link_bblock (cfg, bblock, default_bblock);
8913                                 for (i = 0; i < n; ++i)
8914                                         link_bblock (cfg, bblock, targets [i]);
8915
8916                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8917                                 sp = stack_start;
8918                                 CHECK_UNVERIFIABLE (cfg);
8919                         }
8920
8921                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8922                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8923                         bblock = cfg->cbb;
8924
8925                         for (i = 0; i < n; ++i)
8926                                 link_bblock (cfg, bblock, targets [i]);
8927
8928                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8929                         table->table = targets;
8930                         table->table_size = n;
8931
8932                         use_op_switch = FALSE;
8933 #ifdef TARGET_ARM
8934                         /* ARM implements SWITCH statements differently */
8935                         /* FIXME: Make it use the generic implementation */
8936                         if (!cfg->compile_aot)
8937                                 use_op_switch = TRUE;
8938 #endif
8939
8940                         if (COMPILE_LLVM (cfg))
8941                                 use_op_switch = TRUE;
8942
8943                         cfg->cbb->has_jump_table = 1;
8944
8945                         if (use_op_switch) {
8946                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8947                                 ins->sreg1 = src1->dreg;
8948                                 ins->inst_p0 = table;
8949                                 ins->inst_many_bb = targets;
8950                                 ins->klass = GUINT_TO_POINTER (n);
8951                                 MONO_ADD_INS (cfg->cbb, ins);
8952                         } else {
8953                                 if (sizeof (gpointer) == 8)
8954                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8955                                 else
8956                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8957
8958 #if SIZEOF_REGISTER == 8
8959                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8960                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8961 #endif
8962
8963                                 if (cfg->compile_aot) {
8964                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8965                                 } else {
8966                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8967                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8968                                         ins->inst_p0 = table;
8969                                         ins->dreg = table_reg;
8970                                         MONO_ADD_INS (cfg->cbb, ins);
8971                                 }
8972
8973                                 /* FIXME: Use load_memindex */
8974                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8975                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8976                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8977                         }
8978                         start_new_bblock = 1;
8979                         inline_costs += (BRANCH_COST * 2);
8980                         break;
8981                 }
8982                 case CEE_LDIND_I1:
8983                 case CEE_LDIND_U1:
8984                 case CEE_LDIND_I2:
8985                 case CEE_LDIND_U2:
8986                 case CEE_LDIND_I4:
8987                 case CEE_LDIND_U4:
8988                 case CEE_LDIND_I8:
8989                 case CEE_LDIND_I:
8990                 case CEE_LDIND_R4:
8991                 case CEE_LDIND_R8:
8992                 case CEE_LDIND_REF:
8993                         CHECK_STACK (1);
8994                         --sp;
8995
8996                         switch (*ip) {
8997                         case CEE_LDIND_R4:
8998                         case CEE_LDIND_R8:
8999                                 dreg = alloc_freg (cfg);
9000                                 break;
9001                         case CEE_LDIND_I8:
9002                                 dreg = alloc_lreg (cfg);
9003                                 break;
9004                         case CEE_LDIND_REF:
9005                                 dreg = alloc_ireg_ref (cfg);
9006                                 break;
9007                         default:
9008                                 dreg = alloc_preg (cfg);
9009                         }
9010
9011                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9012                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9013                         ins->flags |= ins_flag;
9014                         ins_flag = 0;
9015                         MONO_ADD_INS (bblock, ins);
9016                         *sp++ = ins;
9017                         if (ins->flags & MONO_INST_VOLATILE) {
9018                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9019                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9020                                 emit_memory_barrier (cfg, FullBarrier);
9021                         }
9022                         ++ip;
9023                         break;
9024                 case CEE_STIND_REF:
9025                 case CEE_STIND_I1:
9026                 case CEE_STIND_I2:
9027                 case CEE_STIND_I4:
9028                 case CEE_STIND_I8:
9029                 case CEE_STIND_R4:
9030                 case CEE_STIND_R8:
9031                 case CEE_STIND_I:
9032                         CHECK_STACK (2);
9033                         sp -= 2;
9034
9035                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9036                         ins->flags |= ins_flag;
9037                         ins_flag = 0;
9038
9039                         if (ins->flags & MONO_INST_VOLATILE) {
9040                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9041                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9042                                 emit_memory_barrier (cfg, FullBarrier);
9043                         }
9044
9045                         MONO_ADD_INS (bblock, ins);
9046
9047                         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)))
9048                                 emit_write_barrier (cfg, sp [0], sp [1]);
9049
9050                         inline_costs += 1;
9051                         ++ip;
9052                         break;
9053
9054                 case CEE_MUL:
9055                         CHECK_STACK (2);
9056
9057                         MONO_INST_NEW (cfg, ins, (*ip));
9058                         sp -= 2;
9059                         ins->sreg1 = sp [0]->dreg;
9060                         ins->sreg2 = sp [1]->dreg;
9061                         type_from_op (ins, sp [0], sp [1]);
9062                         CHECK_TYPE (ins);
9063                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9064
9065                         /* Use the immediate opcodes if possible */
9066                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9067                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9068                                 if (imm_opcode != -1) {
9069                                         ins->opcode = imm_opcode;
9070                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9071                                         ins->sreg2 = -1;
9072
9073                                         sp [1]->opcode = OP_NOP;
9074                                 }
9075                         }
9076
9077                         MONO_ADD_INS ((cfg)->cbb, (ins));
9078
9079                         *sp++ = mono_decompose_opcode (cfg, ins);
9080                         ip++;
9081                         break;
9082                 case CEE_ADD:
9083                 case CEE_SUB:
9084                 case CEE_DIV:
9085                 case CEE_DIV_UN:
9086                 case CEE_REM:
9087                 case CEE_REM_UN:
9088                 case CEE_AND:
9089                 case CEE_OR:
9090                 case CEE_XOR:
9091                 case CEE_SHL:
9092                 case CEE_SHR:
9093                 case CEE_SHR_UN:
9094                         CHECK_STACK (2);
9095
9096                         MONO_INST_NEW (cfg, ins, (*ip));
9097                         sp -= 2;
9098                         ins->sreg1 = sp [0]->dreg;
9099                         ins->sreg2 = sp [1]->dreg;
9100                         type_from_op (ins, sp [0], sp [1]);
9101                         CHECK_TYPE (ins);
9102                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9103                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9104
9105                         /* FIXME: Pass opcode to is_inst_imm */
9106
9107                         /* Use the immediate opcodes if possible */
9108                         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)) {
9109                                 int imm_opcode;
9110
9111                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9112 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9113                                 /* Keep emulated opcodes which are optimized away later */
9114                                 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) {
9115                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9116                                 }
9117 #endif
9118                                 if (imm_opcode != -1) {
9119                                         ins->opcode = imm_opcode;
9120                                         if (sp [1]->opcode == OP_I8CONST) {
9121 #if SIZEOF_REGISTER == 8
9122                                                 ins->inst_imm = sp [1]->inst_l;
9123 #else
9124                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9125                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9126 #endif
9127                                         }
9128                                         else
9129                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9130                                         ins->sreg2 = -1;
9131
9132                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9133                                         if (sp [1]->next == NULL)
9134                                                 sp [1]->opcode = OP_NOP;
9135                                 }
9136                         }
9137                         MONO_ADD_INS ((cfg)->cbb, (ins));
9138
9139                         *sp++ = mono_decompose_opcode (cfg, ins);
9140                         ip++;
9141                         break;
9142                 case CEE_NEG:
9143                 case CEE_NOT:
9144                 case CEE_CONV_I1:
9145                 case CEE_CONV_I2:
9146                 case CEE_CONV_I4:
9147                 case CEE_CONV_R4:
9148                 case CEE_CONV_R8:
9149                 case CEE_CONV_U4:
9150                 case CEE_CONV_I8:
9151                 case CEE_CONV_U8:
9152                 case CEE_CONV_OVF_I8:
9153                 case CEE_CONV_OVF_U8:
9154                 case CEE_CONV_R_UN:
9155                         CHECK_STACK (1);
9156
9157                         /* Special case this earlier so we have long constants in the IR */
9158                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9159                                 int data = sp [-1]->inst_c0;
9160                                 sp [-1]->opcode = OP_I8CONST;
9161                                 sp [-1]->type = STACK_I8;
9162 #if SIZEOF_REGISTER == 8
9163                                 if ((*ip) == CEE_CONV_U8)
9164                                         sp [-1]->inst_c0 = (guint32)data;
9165                                 else
9166                                         sp [-1]->inst_c0 = data;
9167 #else
9168                                 sp [-1]->inst_ls_word = data;
9169                                 if ((*ip) == CEE_CONV_U8)
9170                                         sp [-1]->inst_ms_word = 0;
9171                                 else
9172                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9173 #endif
9174                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9175                         }
9176                         else {
9177                                 ADD_UNOP (*ip);
9178                         }
9179                         ip++;
9180                         break;
9181                 case CEE_CONV_OVF_I4:
9182                 case CEE_CONV_OVF_I1:
9183                 case CEE_CONV_OVF_I2:
9184                 case CEE_CONV_OVF_I:
9185                 case CEE_CONV_OVF_U:
9186                         CHECK_STACK (1);
9187
9188                         if (sp [-1]->type == STACK_R8) {
9189                                 ADD_UNOP (CEE_CONV_OVF_I8);
9190                                 ADD_UNOP (*ip);
9191                         } else {
9192                                 ADD_UNOP (*ip);
9193                         }
9194                         ip++;
9195                         break;
9196                 case CEE_CONV_OVF_U1:
9197                 case CEE_CONV_OVF_U2:
9198                 case CEE_CONV_OVF_U4:
9199                         CHECK_STACK (1);
9200
9201                         if (sp [-1]->type == STACK_R8) {
9202                                 ADD_UNOP (CEE_CONV_OVF_U8);
9203                                 ADD_UNOP (*ip);
9204                         } else {
9205                                 ADD_UNOP (*ip);
9206                         }
9207                         ip++;
9208                         break;
9209                 case CEE_CONV_OVF_I1_UN:
9210                 case CEE_CONV_OVF_I2_UN:
9211                 case CEE_CONV_OVF_I4_UN:
9212                 case CEE_CONV_OVF_I8_UN:
9213                 case CEE_CONV_OVF_U1_UN:
9214                 case CEE_CONV_OVF_U2_UN:
9215                 case CEE_CONV_OVF_U4_UN:
9216                 case CEE_CONV_OVF_U8_UN:
9217                 case CEE_CONV_OVF_I_UN:
9218                 case CEE_CONV_OVF_U_UN:
9219                 case CEE_CONV_U2:
9220                 case CEE_CONV_U1:
9221                 case CEE_CONV_I:
9222                 case CEE_CONV_U:
9223                         CHECK_STACK (1);
9224                         ADD_UNOP (*ip);
9225                         CHECK_CFG_EXCEPTION;
9226                         ip++;
9227                         break;
9228                 case CEE_ADD_OVF:
9229                 case CEE_ADD_OVF_UN:
9230                 case CEE_MUL_OVF:
9231                 case CEE_MUL_OVF_UN:
9232                 case CEE_SUB_OVF:
9233                 case CEE_SUB_OVF_UN:
9234                         CHECK_STACK (2);
9235                         ADD_BINOP (*ip);
9236                         ip++;
9237                         break;
9238                 case CEE_CPOBJ:
9239                         GSHAREDVT_FAILURE (*ip);
9240                         CHECK_OPSIZE (5);
9241                         CHECK_STACK (2);
9242                         token = read32 (ip + 1);
9243                         klass = mini_get_class (method, token, generic_context);
9244                         CHECK_TYPELOAD (klass);
9245                         sp -= 2;
9246                         if (generic_class_is_reference_type (cfg, klass)) {
9247                                 MonoInst *store, *load;
9248                                 int dreg = alloc_ireg_ref (cfg);
9249
9250                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9251                                 load->flags |= ins_flag;
9252                                 MONO_ADD_INS (cfg->cbb, load);
9253
9254                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9255                                 store->flags |= ins_flag;
9256                                 MONO_ADD_INS (cfg->cbb, store);
9257
9258                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9259                                         emit_write_barrier (cfg, sp [0], sp [1]);
9260                         } else {
9261                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9262                         }
9263                         ins_flag = 0;
9264                         ip += 5;
9265                         break;
9266                 case CEE_LDOBJ: {
9267                         int loc_index = -1;
9268                         int stloc_len = 0;
9269
9270                         CHECK_OPSIZE (5);
9271                         CHECK_STACK (1);
9272                         --sp;
9273                         token = read32 (ip + 1);
9274                         klass = mini_get_class (method, token, generic_context);
9275                         CHECK_TYPELOAD (klass);
9276
9277                         /* Optimize the common ldobj+stloc combination */
9278                         switch (ip [5]) {
9279                         case CEE_STLOC_S:
9280                                 loc_index = ip [6];
9281                                 stloc_len = 2;
9282                                 break;
9283                         case CEE_STLOC_0:
9284                         case CEE_STLOC_1:
9285                         case CEE_STLOC_2:
9286                         case CEE_STLOC_3:
9287                                 loc_index = ip [5] - CEE_STLOC_0;
9288                                 stloc_len = 1;
9289                                 break;
9290                         default:
9291                                 break;
9292                         }
9293
9294                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9295                                 CHECK_LOCAL (loc_index);
9296
9297                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9298                                 ins->dreg = cfg->locals [loc_index]->dreg;
9299                                 ip += 5;
9300                                 ip += stloc_len;
9301                                 break;
9302                         }
9303
9304                         /* Optimize the ldobj+stobj combination */
9305                         /* The reference case ends up being a load+store anyway */
9306                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9307                                 CHECK_STACK (1);
9308
9309                                 sp --;
9310
9311                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9312
9313                                 ip += 5 + 5;
9314                                 ins_flag = 0;
9315                                 break;
9316                         }
9317
9318                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9319                         *sp++ = ins;
9320
9321                         ip += 5;
9322                         ins_flag = 0;
9323                         inline_costs += 1;
9324                         break;
9325                 }
9326                 case CEE_LDSTR:
9327                         CHECK_STACK_OVF (1);
9328                         CHECK_OPSIZE (5);
9329                         n = read32 (ip + 1);
9330
9331                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9332                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9333                                 ins->type = STACK_OBJ;
9334                                 *sp = ins;
9335                         }
9336                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9337                                 MonoInst *iargs [1];
9338
9339                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9340                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9341                         } else {
9342                                 if (cfg->opt & MONO_OPT_SHARED) {
9343                                         MonoInst *iargs [3];
9344
9345                                         if (cfg->compile_aot) {
9346                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9347                                         }
9348                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9349                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9350                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9351                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9352                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9353                                 } else {
9354                                         if (bblock->out_of_line) {
9355                                                 MonoInst *iargs [2];
9356
9357                                                 if (image == mono_defaults.corlib) {
9358                                                         /* 
9359                                                          * Avoid relocations in AOT and save some space by using a 
9360                                                          * version of helper_ldstr specialized to mscorlib.
9361                                                          */
9362                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9363                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9364                                                 } else {
9365                                                         /* Avoid creating the string object */
9366                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9367                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9368                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9369                                                 }
9370                                         } 
9371                                         else
9372                                         if (cfg->compile_aot) {
9373                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9374                                                 *sp = ins;
9375                                                 MONO_ADD_INS (bblock, ins);
9376                                         } 
9377                                         else {
9378                                                 NEW_PCONST (cfg, ins, NULL);
9379                                                 ins->type = STACK_OBJ;
9380                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9381                                                 if (!ins->inst_p0)
9382                                                         OUT_OF_MEMORY_FAILURE;
9383
9384                                                 *sp = ins;
9385                                                 MONO_ADD_INS (bblock, ins);
9386                                         }
9387                                 }
9388                         }
9389
9390                         sp++;
9391                         ip += 5;
9392                         break;
9393                 case CEE_NEWOBJ: {
9394                         MonoInst *iargs [2];
9395                         MonoMethodSignature *fsig;
9396                         MonoInst this_ins;
9397                         MonoInst *alloc;
9398                         MonoInst *vtable_arg = NULL;
9399
9400                         CHECK_OPSIZE (5);
9401                         token = read32 (ip + 1);
9402                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9403                         if (!cmethod || mono_loader_get_last_error ())
9404                                 LOAD_ERROR;
9405                         fsig = mono_method_get_signature (cmethod, image, token);
9406                         if (!fsig)
9407                                 LOAD_ERROR;
9408
9409                         mono_save_token_info (cfg, image, token, cmethod);
9410
9411                         if (!mono_class_init (cmethod->klass))
9412                                 TYPE_LOAD_ERROR (cmethod->klass);
9413
9414                         context_used = mini_method_check_context_used (cfg, cmethod);
9415
9416                         if (mono_security_cas_enabled ()) {
9417                                 if (check_linkdemand (cfg, method, cmethod))
9418                                         INLINE_FAILURE ("linkdemand");
9419                                 CHECK_CFG_EXCEPTION;
9420                         } else if (mono_security_core_clr_enabled ()) {
9421                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9422                         }
9423
9424                         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)) {
9425                                 emit_generic_class_init (cfg, cmethod->klass);
9426                                 CHECK_TYPELOAD (cmethod->klass);
9427                         }
9428
9429                         /*
9430                         if (cfg->gsharedvt) {
9431                                 if (mini_is_gsharedvt_variable_signature (sig))
9432                                         GSHAREDVT_FAILURE (*ip);
9433                         }
9434                         */
9435
9436                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9437                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9438                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9439                                         mono_class_vtable (cfg->domain, cmethod->klass);
9440                                         CHECK_TYPELOAD (cmethod->klass);
9441
9442                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9443                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9444                                 } else {
9445                                         if (context_used) {
9446                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9447                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9448                                         } else {
9449                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9450
9451                                                 CHECK_TYPELOAD (cmethod->klass);
9452                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9453                                         }
9454                                 }
9455                         }
9456
9457                         n = fsig->param_count;
9458                         CHECK_STACK (n);
9459
9460                         /* 
9461                          * Generate smaller code for the common newobj <exception> instruction in
9462                          * argument checking code.
9463                          */
9464                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9465                                 is_exception_class (cmethod->klass) && n <= 2 &&
9466                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9467                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9468                                 MonoInst *iargs [3];
9469
9470                                 g_assert (!vtable_arg);
9471
9472                                 sp -= n;
9473
9474                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9475                                 switch (n) {
9476                                 case 0:
9477                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9478                                         break;
9479                                 case 1:
9480                                         iargs [1] = sp [0];
9481                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9482                                         break;
9483                                 case 2:
9484                                         iargs [1] = sp [0];
9485                                         iargs [2] = sp [1];
9486                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9487                                         break;
9488                                 default:
9489                                         g_assert_not_reached ();
9490                                 }
9491
9492                                 ip += 5;
9493                                 inline_costs += 5;
9494                                 break;
9495                         }
9496
9497                         /* move the args to allow room for 'this' in the first position */
9498                         while (n--) {
9499                                 --sp;
9500                                 sp [1] = sp [0];
9501                         }
9502
9503                         /* check_call_signature () requires sp[0] to be set */
9504                         this_ins.type = STACK_OBJ;
9505                         sp [0] = &this_ins;
9506                         if (check_call_signature (cfg, fsig, sp))
9507                                 UNVERIFIED;
9508
9509                         iargs [0] = NULL;
9510
9511                         if (mini_class_is_system_array (cmethod->klass)) {
9512                                 g_assert (!vtable_arg);
9513
9514                                 *sp = emit_get_rgctx_method (cfg, context_used,
9515                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9516
9517                                 /* Avoid varargs in the common case */
9518                                 if (fsig->param_count == 1)
9519                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9520                                 else if (fsig->param_count == 2)
9521                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9522                                 else if (fsig->param_count == 3)
9523                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9524                                 else if (fsig->param_count == 4)
9525                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9526                                 else
9527                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9528                         } else if (cmethod->string_ctor) {
9529                                 g_assert (!context_used);
9530                                 g_assert (!vtable_arg);
9531                                 /* we simply pass a null pointer */
9532                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9533                                 /* now call the string ctor */
9534                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9535                         } else {
9536                                 MonoInst* callvirt_this_arg = NULL;
9537                                 
9538                                 if (cmethod->klass->valuetype) {
9539                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9540                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9541                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9542
9543                                         alloc = NULL;
9544
9545                                         /* 
9546                                          * The code generated by mini_emit_virtual_call () expects
9547                                          * iargs [0] to be a boxed instance, but luckily the vcall
9548                                          * will be transformed into a normal call there.
9549                                          */
9550                                 } else if (context_used) {
9551                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9552                                         *sp = alloc;
9553                                 } else {
9554                                         MonoVTable *vtable = NULL;
9555
9556                                         if (!cfg->compile_aot)
9557                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9558                                         CHECK_TYPELOAD (cmethod->klass);
9559
9560                                         /*
9561                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9562                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9563                                          * As a workaround, we call class cctors before allocating objects.
9564                                          */
9565                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9566                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9567                                                 if (cfg->verbose_level > 2)
9568                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9569                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9570                                         }
9571
9572                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9573                                         *sp = alloc;
9574                                 }
9575                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9576
9577                                 if (alloc)
9578                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9579
9580                                 /* Now call the actual ctor */
9581                                 /* Avoid virtual calls to ctors if possible */
9582                                 if (mono_class_is_marshalbyref (cmethod->klass))
9583                                         callvirt_this_arg = sp [0];
9584
9585
9586                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9587                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9588                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9589                                                 *sp = ins;
9590                                                 sp++;
9591                                         }
9592
9593                                         CHECK_CFG_EXCEPTION;
9594                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9595                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9596                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9597                                     !g_list_find (dont_inline, cmethod)) {
9598                                         int costs;
9599
9600                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9601                                                 cfg->real_offset += 5;
9602                                                 bblock = cfg->cbb;
9603
9604                                                 inline_costs += costs - 5;
9605                                         } else {
9606                                                 INLINE_FAILURE ("inline failure");
9607                                                 // FIXME-VT: Clean this up
9608                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9609                                                         GSHAREDVT_FAILURE(*ip);
9610                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9611                                         }
9612                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9613                                         MonoInst *addr;
9614
9615                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9616                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9617                                 } else if (context_used &&
9618                                                    ((!mono_method_is_generic_sharable (cmethod, TRUE) ||
9619                                                          !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
9620                                         MonoInst *cmethod_addr;
9621
9622                                         /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
9623
9624                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9625                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9626
9627                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9628                                 } else {
9629                                         INLINE_FAILURE ("ctor call");
9630                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9631                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9632                                 }
9633                         }
9634
9635                         if (alloc == NULL) {
9636                                 /* Valuetype */
9637                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9638                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9639                                 *sp++= ins;
9640                         }
9641                         else
9642                                 *sp++ = alloc;
9643                         
9644                         ip += 5;
9645                         inline_costs += 5;
9646                         break;
9647                 }
9648                 case CEE_CASTCLASS:
9649                         CHECK_STACK (1);
9650                         --sp;
9651                         CHECK_OPSIZE (5);
9652                         token = read32 (ip + 1);
9653                         klass = mini_get_class (method, token, generic_context);
9654                         CHECK_TYPELOAD (klass);
9655                         if (sp [0]->type != STACK_OBJ)
9656                                 UNVERIFIED;
9657
9658                         context_used = mini_class_check_context_used (cfg, klass);
9659
9660                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9661                                 MonoInst *args [3];
9662
9663                                 /* obj */
9664                                 args [0] = *sp;
9665
9666                                 /* klass */
9667                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9668
9669                                 /* inline cache*/
9670                                 if (cfg->compile_aot)
9671                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9672                                 else
9673                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9674
9675                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9676
9677                                 *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9678                                 ip += 5;
9679                                 inline_costs += 2;
9680                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9681                                 MonoMethod *mono_castclass;
9682                                 MonoInst *iargs [1];
9683                                 int costs;
9684
9685                                 mono_castclass = mono_marshal_get_castclass (klass); 
9686                                 iargs [0] = sp [0];
9687                                 
9688                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9689                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9690                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9691                                 reset_cast_details (cfg);
9692                                 CHECK_CFG_EXCEPTION;
9693                                 g_assert (costs > 0);
9694                                 
9695                                 ip += 5;
9696                                 cfg->real_offset += 5;
9697                                 bblock = cfg->cbb;
9698
9699                                 *sp++ = iargs [0];
9700
9701                                 inline_costs += costs;
9702                         }
9703                         else {
9704                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9705                                 CHECK_CFG_EXCEPTION;
9706                                 bblock = cfg->cbb;
9707                                 *sp ++ = ins;
9708                                 ip += 5;
9709                         }
9710                         break;
9711                 case CEE_ISINST: {
9712                         CHECK_STACK (1);
9713                         --sp;
9714                         CHECK_OPSIZE (5);
9715                         token = read32 (ip + 1);
9716                         klass = mini_get_class (method, token, generic_context);
9717                         CHECK_TYPELOAD (klass);
9718                         if (sp [0]->type != STACK_OBJ)
9719                                 UNVERIFIED;
9720  
9721                         context_used = mini_class_check_context_used (cfg, klass);
9722
9723                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9724                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9725                                 MonoInst *args [3];
9726
9727                                 /* obj */
9728                                 args [0] = *sp;
9729
9730                                 /* klass */
9731                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9732
9733                                 /* inline cache*/
9734                                 if (cfg->compile_aot)
9735                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9736                                 else
9737                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9738
9739                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9740                                 ip += 5;
9741                                 inline_costs += 2;
9742                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9743                                 MonoMethod *mono_isinst;
9744                                 MonoInst *iargs [1];
9745                                 int costs;
9746
9747                                 mono_isinst = mono_marshal_get_isinst (klass); 
9748                                 iargs [0] = sp [0];
9749
9750                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9751                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9752                                 CHECK_CFG_EXCEPTION;
9753                                 g_assert (costs > 0);
9754                                 
9755                                 ip += 5;
9756                                 cfg->real_offset += 5;
9757                                 bblock = cfg->cbb;
9758
9759                                 *sp++= iargs [0];
9760
9761                                 inline_costs += costs;
9762                         }
9763                         else {
9764                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9765                                 CHECK_CFG_EXCEPTION;
9766                                 bblock = cfg->cbb;
9767                                 *sp ++ = ins;
9768                                 ip += 5;
9769                         }
9770                         break;
9771                 }
9772                 case CEE_UNBOX_ANY: {
9773                         CHECK_STACK (1);
9774                         --sp;
9775                         CHECK_OPSIZE (5);
9776                         token = read32 (ip + 1);
9777                         klass = mini_get_class (method, token, generic_context);
9778                         CHECK_TYPELOAD (klass);
9779  
9780                         mono_save_token_info (cfg, image, token, klass);
9781
9782                         context_used = mini_class_check_context_used (cfg, klass);
9783
9784                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9785                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9786                                 sp ++;
9787
9788                                 ip += 5;
9789                                 inline_costs += 2;
9790                                 break;
9791                         }
9792
9793                         if (generic_class_is_reference_type (cfg, klass)) {
9794                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9795                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9796                                         MonoInst *args [3];
9797
9798                                         /* obj */
9799                                         args [0] = *sp;
9800
9801                                         /* klass */
9802                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9803
9804                                         /* inline cache*/
9805                                         /*FIXME AOT support*/
9806                                         if (cfg->compile_aot)
9807                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9808                                         else
9809                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9810
9811                                         /* The wrapper doesn't inline well so the bloat of inlining doesn't pay off. */
9812                                         *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9813                                         ip += 5;
9814                                         inline_costs += 2;
9815                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9816                                         MonoMethod *mono_castclass;
9817                                         MonoInst *iargs [1];
9818                                         int costs;
9819
9820                                         mono_castclass = mono_marshal_get_castclass (klass); 
9821                                         iargs [0] = sp [0];
9822
9823                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9824                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9825                                         CHECK_CFG_EXCEPTION;
9826                                         g_assert (costs > 0);
9827                                 
9828                                         ip += 5;
9829                                         cfg->real_offset += 5;
9830                                         bblock = cfg->cbb;
9831
9832                                         *sp++ = iargs [0];
9833                                         inline_costs += costs;
9834                                 } else {
9835                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9836                                         CHECK_CFG_EXCEPTION;
9837                                         bblock = cfg->cbb;
9838                                         *sp ++ = ins;
9839                                         ip += 5;
9840                                 }
9841                                 break;
9842                         }
9843
9844                         if (mono_class_is_nullable (klass)) {
9845                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9846                                 *sp++= ins;
9847                                 ip += 5;
9848                                 break;
9849                         }
9850
9851                         /* UNBOX */
9852                         ins = handle_unbox (cfg, klass, sp, context_used);
9853                         *sp = ins;
9854
9855                         ip += 5;
9856
9857                         /* LDOBJ */
9858                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9859                         *sp++ = ins;
9860
9861                         inline_costs += 2;
9862                         break;
9863                 }
9864                 case CEE_BOX: {
9865                         MonoInst *val;
9866
9867                         CHECK_STACK (1);
9868                         --sp;
9869                         val = *sp;
9870                         CHECK_OPSIZE (5);
9871                         token = read32 (ip + 1);
9872                         klass = mini_get_class (method, token, generic_context);
9873                         CHECK_TYPELOAD (klass);
9874
9875                         mono_save_token_info (cfg, image, token, klass);
9876
9877                         context_used = mini_class_check_context_used (cfg, klass);
9878
9879                         if (generic_class_is_reference_type (cfg, klass)) {
9880                                 *sp++ = val;
9881                                 ip += 5;
9882                                 break;
9883                         }
9884
9885                         if (klass == mono_defaults.void_class)
9886                                 UNVERIFIED;
9887                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9888                                 UNVERIFIED;
9889                         /* frequent check in generic code: box (struct), brtrue */
9890
9891                         // FIXME: LLVM can't handle the inconsistent bb linking
9892                         if (!mono_class_is_nullable (klass) &&
9893                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9894                                 (ip [5] == CEE_BRTRUE || 
9895                                  ip [5] == CEE_BRTRUE_S ||
9896                                  ip [5] == CEE_BRFALSE ||
9897                                  ip [5] == CEE_BRFALSE_S)) {
9898                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9899                                 int dreg;
9900                                 MonoBasicBlock *true_bb, *false_bb;
9901
9902                                 ip += 5;
9903
9904                                 if (cfg->verbose_level > 3) {
9905                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9906                                         printf ("<box+brtrue opt>\n");
9907                                 }
9908
9909                                 switch (*ip) {
9910                                 case CEE_BRTRUE_S:
9911                                 case CEE_BRFALSE_S:
9912                                         CHECK_OPSIZE (2);
9913                                         ip++;
9914                                         target = ip + 1 + (signed char)(*ip);
9915                                         ip++;
9916                                         break;
9917                                 case CEE_BRTRUE:
9918                                 case CEE_BRFALSE:
9919                                         CHECK_OPSIZE (5);
9920                                         ip++;
9921                                         target = ip + 4 + (gint)(read32 (ip));
9922                                         ip += 4;
9923                                         break;
9924                                 default:
9925                                         g_assert_not_reached ();
9926                                 }
9927
9928                                 /* 
9929                                  * We need to link both bblocks, since it is needed for handling stack
9930                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9931                                  * Branching to only one of them would lead to inconsistencies, so
9932                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9933                                  */
9934                                 GET_BBLOCK (cfg, true_bb, target);
9935                                 GET_BBLOCK (cfg, false_bb, ip);
9936
9937                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9938                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9939
9940                                 if (sp != stack_start) {
9941                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9942                                         sp = stack_start;
9943                                         CHECK_UNVERIFIABLE (cfg);
9944                                 }
9945
9946                                 if (COMPILE_LLVM (cfg)) {
9947                                         dreg = alloc_ireg (cfg);
9948                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9949                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9950
9951                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9952                                 } else {
9953                                         /* The JIT can't eliminate the iconst+compare */
9954                                         MONO_INST_NEW (cfg, ins, OP_BR);
9955                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9956                                         MONO_ADD_INS (cfg->cbb, ins);
9957                                 }
9958
9959                                 start_new_bblock = 1;
9960                                 break;
9961                         }
9962
9963                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9964
9965                         CHECK_CFG_EXCEPTION;
9966                         ip += 5;
9967                         inline_costs += 1;
9968                         break;
9969                 }
9970                 case CEE_UNBOX: {
9971                         CHECK_STACK (1);
9972                         --sp;
9973                         CHECK_OPSIZE (5);
9974                         token = read32 (ip + 1);
9975                         klass = mini_get_class (method, token, generic_context);
9976                         CHECK_TYPELOAD (klass);
9977
9978                         mono_save_token_info (cfg, image, token, klass);
9979
9980                         context_used = mini_class_check_context_used (cfg, klass);
9981
9982                         if (mono_class_is_nullable (klass)) {
9983                                 MonoInst *val;
9984
9985                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9986                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9987
9988                                 *sp++= ins;
9989                         } else {
9990                                 ins = handle_unbox (cfg, klass, sp, context_used);
9991                                 *sp++ = ins;
9992                         }
9993                         ip += 5;
9994                         inline_costs += 2;
9995                         break;
9996                 }
9997                 case CEE_LDFLD:
9998                 case CEE_LDFLDA:
9999                 case CEE_STFLD:
10000                 case CEE_LDSFLD:
10001                 case CEE_LDSFLDA:
10002                 case CEE_STSFLD: {
10003                         MonoClassField *field;
10004 #ifndef DISABLE_REMOTING
10005                         int costs;
10006 #endif
10007                         guint foffset;
10008                         gboolean is_instance;
10009                         int op;
10010                         gpointer addr = NULL;
10011                         gboolean is_special_static;
10012                         MonoType *ftype;
10013                         MonoInst *store_val = NULL;
10014                         MonoInst *thread_ins;
10015
10016                         op = *ip;
10017                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10018                         if (is_instance) {
10019                                 if (op == CEE_STFLD) {
10020                                         CHECK_STACK (2);
10021                                         sp -= 2;
10022                                         store_val = sp [1];
10023                                 } else {
10024                                         CHECK_STACK (1);
10025                                         --sp;
10026                                 }
10027                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10028                                         UNVERIFIED;
10029                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10030                                         UNVERIFIED;
10031                         } else {
10032                                 if (op == CEE_STSFLD) {
10033                                         CHECK_STACK (1);
10034                                         sp--;
10035                                         store_val = sp [0];
10036                                 }
10037                         }
10038
10039                         CHECK_OPSIZE (5);
10040                         token = read32 (ip + 1);
10041                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10042                                 field = mono_method_get_wrapper_data (method, token);
10043                                 klass = field->parent;
10044                         }
10045                         else {
10046                                 field = mono_field_from_token (image, token, &klass, generic_context);
10047                         }
10048                         if (!field)
10049                                 LOAD_ERROR;
10050                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10051                                 FIELD_ACCESS_FAILURE;
10052                         mono_class_init (klass);
10053
10054                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10055                                 UNVERIFIED;
10056
10057                         /* if the class is Critical then transparent code cannot access it's fields */
10058                         if (!is_instance && mono_security_core_clr_enabled ())
10059                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10060
10061                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10062                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10063                         if (mono_security_core_clr_enabled ())
10064                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10065                         */
10066
10067                         /*
10068                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10069                          * the static case.
10070                          */
10071                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10072                                 switch (op) {
10073                                 case CEE_LDFLD:
10074                                         op = CEE_LDSFLD;
10075                                         break;
10076                                 case CEE_STFLD:
10077                                         op = CEE_STSFLD;
10078                                         break;
10079                                 case CEE_LDFLDA:
10080                                         op = CEE_LDSFLDA;
10081                                         break;
10082                                 default:
10083                                         g_assert_not_reached ();
10084                                 }
10085                                 is_instance = FALSE;
10086                         }
10087
10088                         context_used = mini_class_check_context_used (cfg, klass);
10089
10090                         /* INSTANCE CASE */
10091
10092                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10093                         if (op == CEE_STFLD) {
10094                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10095                                         UNVERIFIED;
10096 #ifndef DISABLE_REMOTING
10097                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10098                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10099                                         MonoInst *iargs [5];
10100
10101                                         GSHAREDVT_FAILURE (op);
10102
10103                                         iargs [0] = sp [0];
10104                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10105                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10106                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10107                                                     field->offset);
10108                                         iargs [4] = sp [1];
10109
10110                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10111                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10112                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
10113                                                 CHECK_CFG_EXCEPTION;
10114                                                 g_assert (costs > 0);
10115                                                       
10116                                                 cfg->real_offset += 5;
10117                                                 bblock = cfg->cbb;
10118
10119                                                 inline_costs += costs;
10120                                         } else {
10121                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10122                                         }
10123                                 } else
10124 #endif
10125                                 {
10126                                         MonoInst *store;
10127
10128                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10129
10130                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10131                                                 MonoInst *offset_ins;
10132
10133                                                 context_used = mini_class_check_context_used (cfg, klass);
10134
10135                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10136                                                 dreg = alloc_ireg_mp (cfg);
10137                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10138                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10139                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10140                                         } else {
10141                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10142                                         }
10143                                         if (sp [0]->opcode != OP_LDADDR)
10144                                                 store->flags |= MONO_INST_FAULT;
10145
10146                                 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)) {
10147                                         /* insert call to write barrier */
10148                                         MonoInst *ptr;
10149                                         int dreg;
10150
10151                                         dreg = alloc_ireg_mp (cfg);
10152                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10153                                         emit_write_barrier (cfg, ptr, sp [1]);
10154                                 }
10155
10156                                         store->flags |= ins_flag;
10157                                 }
10158                                 ins_flag = 0;
10159                                 ip += 5;
10160                                 break;
10161                         }
10162
10163 #ifndef DISABLE_REMOTING
10164                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10165                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10166                                 MonoInst *iargs [4];
10167
10168                                 GSHAREDVT_FAILURE (op);
10169
10170                                 iargs [0] = sp [0];
10171                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10172                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10173                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10174                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10175                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10176                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
10177                                         CHECK_CFG_EXCEPTION;
10178                                         bblock = cfg->cbb;
10179                                         g_assert (costs > 0);
10180                                                       
10181                                         cfg->real_offset += 5;
10182
10183                                         *sp++ = iargs [0];
10184
10185                                         inline_costs += costs;
10186                                 } else {
10187                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10188                                         *sp++ = ins;
10189                                 }
10190                         } else 
10191 #endif
10192                         if (is_instance) {
10193                                 if (sp [0]->type == STACK_VTYPE) {
10194                                         MonoInst *var;
10195
10196                                         /* Have to compute the address of the variable */
10197
10198                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10199                                         if (!var)
10200                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10201                                         else
10202                                                 g_assert (var->klass == klass);
10203                                         
10204                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10205                                         sp [0] = ins;
10206                                 }
10207
10208                                 if (op == CEE_LDFLDA) {
10209                                         if (is_magic_tls_access (field)) {
10210                                                 GSHAREDVT_FAILURE (*ip);
10211                                                 ins = sp [0];
10212                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10213                                         } else {
10214                                                 if (sp [0]->type == STACK_OBJ) {
10215                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10216                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10217                                                 }
10218
10219                                                 dreg = alloc_ireg_mp (cfg);
10220
10221                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10222                                                         MonoInst *offset_ins;
10223
10224                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10225                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10226                                                 } else {
10227                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10228                                                 }
10229                                                 ins->klass = mono_class_from_mono_type (field->type);
10230                                                 ins->type = STACK_MP;
10231                                                 *sp++ = ins;
10232                                         }
10233                                 } else {
10234                                         MonoInst *load;
10235
10236                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10237
10238                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10239                                                 MonoInst *offset_ins;
10240
10241                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10242                                                 dreg = alloc_ireg_mp (cfg);
10243                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10244                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10245                                         } else {
10246                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10247                                         }
10248                                         load->flags |= ins_flag;
10249                                         if (sp [0]->opcode != OP_LDADDR)
10250                                                 load->flags |= MONO_INST_FAULT;
10251                                         *sp++ = load;
10252                                 }
10253                         }
10254
10255                         if (is_instance) {
10256                                 ins_flag = 0;
10257                                 ip += 5;
10258                                 break;
10259                         }
10260
10261                         /* STATIC CASE */
10262
10263                         /*
10264                          * We can only support shared generic static
10265                          * field access on architectures where the
10266                          * trampoline code has been extended to handle
10267                          * the generic class init.
10268                          */
10269 #ifndef MONO_ARCH_VTABLE_REG
10270                         GENERIC_SHARING_FAILURE (op);
10271 #endif
10272
10273                         context_used = mini_class_check_context_used (cfg, klass);
10274
10275                         ftype = mono_field_get_type (field);
10276
10277                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10278                                 UNVERIFIED;
10279
10280                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10281                          * to be called here.
10282                          */
10283                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10284                                 mono_class_vtable (cfg->domain, klass);
10285                                 CHECK_TYPELOAD (klass);
10286                         }
10287                         mono_domain_lock (cfg->domain);
10288                         if (cfg->domain->special_static_fields)
10289                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10290                         mono_domain_unlock (cfg->domain);
10291
10292                         is_special_static = mono_class_field_is_special_static (field);
10293
10294                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10295                                 thread_ins = mono_get_thread_intrinsic (cfg);
10296                         else
10297                                 thread_ins = NULL;
10298
10299                         /* Generate IR to compute the field address */
10300                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10301                                 /*
10302                                  * Fast access to TLS data
10303                                  * Inline version of get_thread_static_data () in
10304                                  * threads.c.
10305                                  */
10306                                 guint32 offset;
10307                                 int idx, static_data_reg, array_reg, dreg;
10308
10309                                 GSHAREDVT_FAILURE (op);
10310
10311                                 // offset &= 0x7fffffff;
10312                                 // idx = (offset >> 24) - 1;
10313                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10314                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10315                                 static_data_reg = alloc_ireg (cfg);
10316                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10317
10318                                 if (cfg->compile_aot) {
10319                                         int offset_reg, offset2_reg, idx_reg;
10320
10321                                         /* For TLS variables, this will return the TLS offset */
10322                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10323                                         offset_reg = ins->dreg;
10324                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10325                                         idx_reg = alloc_ireg (cfg);
10326                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10327                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10328                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10329                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10330                                         array_reg = alloc_ireg (cfg);
10331                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10332                                         offset2_reg = alloc_ireg (cfg);
10333                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10334                                         dreg = alloc_ireg (cfg);
10335                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10336                                 } else {
10337                                         offset = (gsize)addr & 0x7fffffff;
10338                                         idx = (offset >> 24) - 1;
10339
10340                                         array_reg = alloc_ireg (cfg);
10341                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10342                                         dreg = alloc_ireg (cfg);
10343                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10344                                 }
10345                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10346                                         (cfg->compile_aot && is_special_static) ||
10347                                         (context_used && is_special_static)) {
10348                                 MonoInst *iargs [2];
10349
10350                                 g_assert (field->parent);
10351                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10352                                 if (context_used) {
10353                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10354                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10355                                 } else {
10356                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10357                                 }
10358                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10359                         } else if (context_used) {
10360                                 MonoInst *static_data;
10361
10362                                 /*
10363                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10364                                         method->klass->name_space, method->klass->name, method->name,
10365                                         depth, field->offset);
10366                                 */
10367
10368                                 if (mono_class_needs_cctor_run (klass, method))
10369                                         emit_generic_class_init (cfg, klass);
10370
10371                                 /*
10372                                  * The pointer we're computing here is
10373                                  *
10374                                  *   super_info.static_data + field->offset
10375                                  */
10376                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10377                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10378
10379                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10380                                         MonoInst *offset_ins;
10381
10382                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10383                                         dreg = alloc_ireg_mp (cfg);
10384                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10385                                 } else if (field->offset == 0) {
10386                                         ins = static_data;
10387                                 } else {
10388                                         int addr_reg = mono_alloc_preg (cfg);
10389                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10390                                 }
10391                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10392                                 MonoInst *iargs [2];
10393
10394                                 g_assert (field->parent);
10395                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10396                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10397                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10398                         } else {
10399                                 MonoVTable *vtable = NULL;
10400
10401                                 if (!cfg->compile_aot)
10402                                         vtable = mono_class_vtable (cfg->domain, klass);
10403                                 CHECK_TYPELOAD (klass);
10404
10405                                 if (!addr) {
10406                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10407                                                 if (!(g_slist_find (class_inits, klass))) {
10408                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10409                                                         if (cfg->verbose_level > 2)
10410                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10411                                                         class_inits = g_slist_prepend (class_inits, klass);
10412                                                 }
10413                                         } else {
10414                                                 if (cfg->run_cctors) {
10415                                                         MonoException *ex;
10416                                                         /* This makes so that inline cannot trigger */
10417                                                         /* .cctors: too many apps depend on them */
10418                                                         /* running with a specific order... */
10419                                                         g_assert (vtable);
10420                                                         if (! vtable->initialized)
10421                                                                 INLINE_FAILURE ("class init");
10422                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10423                                                         if (ex) {
10424                                                                 set_exception_object (cfg, ex);
10425                                                                 goto exception_exit;
10426                                                         }
10427                                                 }
10428                                         }
10429                                         if (cfg->compile_aot)
10430                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10431                                         else {
10432                                                 g_assert (vtable);
10433                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10434                                                 g_assert (addr);
10435                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10436                                         }
10437                                 } else {
10438                                         MonoInst *iargs [1];
10439                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10440                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10441                                 }
10442                         }
10443
10444                         /* Generate IR to do the actual load/store operation */
10445
10446                         if (op == CEE_LDSFLDA) {
10447                                 ins->klass = mono_class_from_mono_type (ftype);
10448                                 ins->type = STACK_PTR;
10449                                 *sp++ = ins;
10450                         } else if (op == CEE_STSFLD) {
10451                                 MonoInst *store;
10452
10453                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10454                                 store->flags |= ins_flag;
10455                         } else {
10456                                 gboolean is_const = FALSE;
10457                                 MonoVTable *vtable = NULL;
10458                                 gpointer addr = NULL;
10459
10460                                 if (!context_used) {
10461                                         vtable = mono_class_vtable (cfg->domain, klass);
10462                                         CHECK_TYPELOAD (klass);
10463                                 }
10464                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10465                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10466                                         int ro_type = ftype->type;
10467                                         if (!addr)
10468                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10469                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10470                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10471                                         }
10472
10473                                         GSHAREDVT_FAILURE (op);
10474
10475                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10476                                         is_const = TRUE;
10477                                         switch (ro_type) {
10478                                         case MONO_TYPE_BOOLEAN:
10479                                         case MONO_TYPE_U1:
10480                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10481                                                 sp++;
10482                                                 break;
10483                                         case MONO_TYPE_I1:
10484                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10485                                                 sp++;
10486                                                 break;                                          
10487                                         case MONO_TYPE_CHAR:
10488                                         case MONO_TYPE_U2:
10489                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10490                                                 sp++;
10491                                                 break;
10492                                         case MONO_TYPE_I2:
10493                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10494                                                 sp++;
10495                                                 break;
10496                                                 break;
10497                                         case MONO_TYPE_I4:
10498                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10499                                                 sp++;
10500                                                 break;                                          
10501                                         case MONO_TYPE_U4:
10502                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10503                                                 sp++;
10504                                                 break;
10505                                         case MONO_TYPE_I:
10506                                         case MONO_TYPE_U:
10507                                         case MONO_TYPE_PTR:
10508                                         case MONO_TYPE_FNPTR:
10509                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10510                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10511                                                 sp++;
10512                                                 break;
10513                                         case MONO_TYPE_STRING:
10514                                         case MONO_TYPE_OBJECT:
10515                                         case MONO_TYPE_CLASS:
10516                                         case MONO_TYPE_SZARRAY:
10517                                         case MONO_TYPE_ARRAY:
10518                                                 if (!mono_gc_is_moving ()) {
10519                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10520                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10521                                                         sp++;
10522                                                 } else {
10523                                                         is_const = FALSE;
10524                                                 }
10525                                                 break;
10526                                         case MONO_TYPE_I8:
10527                                         case MONO_TYPE_U8:
10528                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10529                                                 sp++;
10530                                                 break;
10531                                         case MONO_TYPE_R4:
10532                                         case MONO_TYPE_R8:
10533                                         case MONO_TYPE_VALUETYPE:
10534                                         default:
10535                                                 is_const = FALSE;
10536                                                 break;
10537                                         }
10538                                 }
10539
10540                                 if (!is_const) {
10541                                         MonoInst *load;
10542
10543                                         CHECK_STACK_OVF (1);
10544
10545                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10546                                         load->flags |= ins_flag;
10547                                         ins_flag = 0;
10548                                         *sp++ = load;
10549                                 }
10550                         }
10551                         ins_flag = 0;
10552                         ip += 5;
10553                         break;
10554                 }
10555                 case CEE_STOBJ:
10556                         CHECK_STACK (2);
10557                         sp -= 2;
10558                         CHECK_OPSIZE (5);
10559                         token = read32 (ip + 1);
10560                         klass = mini_get_class (method, token, generic_context);
10561                         CHECK_TYPELOAD (klass);
10562                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10563                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10564                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10565                                         generic_class_is_reference_type (cfg, klass)) {
10566                                 /* insert call to write barrier */
10567                                 emit_write_barrier (cfg, sp [0], sp [1]);
10568                         }
10569                         ins_flag = 0;
10570                         ip += 5;
10571                         inline_costs += 1;
10572                         break;
10573
10574                         /*
10575                          * Array opcodes
10576                          */
10577                 case CEE_NEWARR: {
10578                         MonoInst *len_ins;
10579                         const char *data_ptr;
10580                         int data_size = 0;
10581                         guint32 field_token;
10582
10583                         CHECK_STACK (1);
10584                         --sp;
10585
10586                         CHECK_OPSIZE (5);
10587                         token = read32 (ip + 1);
10588
10589                         klass = mini_get_class (method, token, generic_context);
10590                         CHECK_TYPELOAD (klass);
10591
10592                         context_used = mini_class_check_context_used (cfg, klass);
10593
10594                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10595                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10596                                 ins->sreg1 = sp [0]->dreg;
10597                                 ins->type = STACK_I4;
10598                                 ins->dreg = alloc_ireg (cfg);
10599                                 MONO_ADD_INS (cfg->cbb, ins);
10600                                 *sp = mono_decompose_opcode (cfg, ins);
10601                         }
10602
10603                         if (context_used) {
10604                                 MonoInst *args [3];
10605                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10606                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10607
10608                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10609
10610                                 /* vtable */
10611                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10612                                         array_class, MONO_RGCTX_INFO_VTABLE);
10613                                 /* array len */
10614                                 args [1] = sp [0];
10615
10616                                 if (managed_alloc)
10617                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10618                                 else
10619                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10620                         } else {
10621                                 if (cfg->opt & MONO_OPT_SHARED) {
10622                                         /* Decompose now to avoid problems with references to the domainvar */
10623                                         MonoInst *iargs [3];
10624
10625                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10626                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10627                                         iargs [2] = sp [0];
10628
10629                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10630                                 } else {
10631                                         /* Decompose later since it is needed by abcrem */
10632                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10633                                         mono_class_vtable (cfg->domain, array_type);
10634                                         CHECK_TYPELOAD (array_type);
10635
10636                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10637                                         ins->dreg = alloc_ireg_ref (cfg);
10638                                         ins->sreg1 = sp [0]->dreg;
10639                                         ins->inst_newa_class = klass;
10640                                         ins->type = STACK_OBJ;
10641                                         ins->klass = array_type;
10642                                         MONO_ADD_INS (cfg->cbb, ins);
10643                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10644                                         cfg->cbb->has_array_access = TRUE;
10645
10646                                         /* Needed so mono_emit_load_get_addr () gets called */
10647                                         mono_get_got_var (cfg);
10648                                 }
10649                         }
10650
10651                         len_ins = sp [0];
10652                         ip += 5;
10653                         *sp++ = ins;
10654                         inline_costs += 1;
10655
10656                         /* 
10657                          * we inline/optimize the initialization sequence if possible.
10658                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10659                          * for small sizes open code the memcpy
10660                          * ensure the rva field is big enough
10661                          */
10662                         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))) {
10663                                 MonoMethod *memcpy_method = get_memcpy_method ();
10664                                 MonoInst *iargs [3];
10665                                 int add_reg = alloc_ireg_mp (cfg);
10666
10667                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10668                                 if (cfg->compile_aot) {
10669                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10670                                 } else {
10671                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10672                                 }
10673                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10674                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10675                                 ip += 11;
10676                         }
10677
10678                         break;
10679                 }
10680                 case CEE_LDLEN:
10681                         CHECK_STACK (1);
10682                         --sp;
10683                         if (sp [0]->type != STACK_OBJ)
10684                                 UNVERIFIED;
10685
10686                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10687                         ins->dreg = alloc_preg (cfg);
10688                         ins->sreg1 = sp [0]->dreg;
10689                         ins->type = STACK_I4;
10690                         /* This flag will be inherited by the decomposition */
10691                         ins->flags |= MONO_INST_FAULT;
10692                         MONO_ADD_INS (cfg->cbb, ins);
10693                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10694                         cfg->cbb->has_array_access = TRUE;
10695                         ip ++;
10696                         *sp++ = ins;
10697                         break;
10698                 case CEE_LDELEMA:
10699                         CHECK_STACK (2);
10700                         sp -= 2;
10701                         CHECK_OPSIZE (5);
10702                         if (sp [0]->type != STACK_OBJ)
10703                                 UNVERIFIED;
10704
10705                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10706
10707                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10708                         CHECK_TYPELOAD (klass);
10709                         /* we need to make sure that this array is exactly the type it needs
10710                          * to be for correctness. the wrappers are lax with their usage
10711                          * so we need to ignore them here
10712                          */
10713                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10714                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10715                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10716                                 CHECK_TYPELOAD (array_class);
10717                         }
10718
10719                         readonly = FALSE;
10720                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10721                         *sp++ = ins;
10722                         ip += 5;
10723                         break;
10724                 case CEE_LDELEM:
10725                 case CEE_LDELEM_I1:
10726                 case CEE_LDELEM_U1:
10727                 case CEE_LDELEM_I2:
10728                 case CEE_LDELEM_U2:
10729                 case CEE_LDELEM_I4:
10730                 case CEE_LDELEM_U4:
10731                 case CEE_LDELEM_I8:
10732                 case CEE_LDELEM_I:
10733                 case CEE_LDELEM_R4:
10734                 case CEE_LDELEM_R8:
10735                 case CEE_LDELEM_REF: {
10736                         MonoInst *addr;
10737
10738                         CHECK_STACK (2);
10739                         sp -= 2;
10740
10741                         if (*ip == CEE_LDELEM) {
10742                                 CHECK_OPSIZE (5);
10743                                 token = read32 (ip + 1);
10744                                 klass = mini_get_class (method, token, generic_context);
10745                                 CHECK_TYPELOAD (klass);
10746                                 mono_class_init (klass);
10747                         }
10748                         else
10749                                 klass = array_access_to_klass (*ip);
10750
10751                         if (sp [0]->type != STACK_OBJ)
10752                                 UNVERIFIED;
10753
10754                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10755
10756                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10757                                 // FIXME-VT: OP_ICONST optimization
10758                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10759                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10760                                 ins->opcode = OP_LOADV_MEMBASE;
10761                         } else if (sp [1]->opcode == OP_ICONST) {
10762                                 int array_reg = sp [0]->dreg;
10763                                 int index_reg = sp [1]->dreg;
10764                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10765
10766                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10767                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10768                         } else {
10769                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10770                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10771                         }
10772                         *sp++ = ins;
10773                         if (*ip == CEE_LDELEM)
10774                                 ip += 5;
10775                         else
10776                                 ++ip;
10777                         break;
10778                 }
10779                 case CEE_STELEM_I:
10780                 case CEE_STELEM_I1:
10781                 case CEE_STELEM_I2:
10782                 case CEE_STELEM_I4:
10783                 case CEE_STELEM_I8:
10784                 case CEE_STELEM_R4:
10785                 case CEE_STELEM_R8:
10786                 case CEE_STELEM_REF:
10787                 case CEE_STELEM: {
10788                         CHECK_STACK (3);
10789                         sp -= 3;
10790
10791                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10792
10793                         if (*ip == CEE_STELEM) {
10794                                 CHECK_OPSIZE (5);
10795                                 token = read32 (ip + 1);
10796                                 klass = mini_get_class (method, token, generic_context);
10797                                 CHECK_TYPELOAD (klass);
10798                                 mono_class_init (klass);
10799                         }
10800                         else
10801                                 klass = array_access_to_klass (*ip);
10802
10803                         if (sp [0]->type != STACK_OBJ)
10804                                 UNVERIFIED;
10805
10806                         emit_array_store (cfg, klass, sp, TRUE);
10807
10808                         if (*ip == CEE_STELEM)
10809                                 ip += 5;
10810                         else
10811                                 ++ip;
10812                         inline_costs += 1;
10813                         break;
10814                 }
10815                 case CEE_CKFINITE: {
10816                         CHECK_STACK (1);
10817                         --sp;
10818
10819                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10820                         ins->sreg1 = sp [0]->dreg;
10821                         ins->dreg = alloc_freg (cfg);
10822                         ins->type = STACK_R8;
10823                         MONO_ADD_INS (bblock, ins);
10824
10825                         *sp++ = mono_decompose_opcode (cfg, ins);
10826
10827                         ++ip;
10828                         break;
10829                 }
10830                 case CEE_REFANYVAL: {
10831                         MonoInst *src_var, *src;
10832
10833                         int klass_reg = alloc_preg (cfg);
10834                         int dreg = alloc_preg (cfg);
10835
10836                         GSHAREDVT_FAILURE (*ip);
10837
10838                         CHECK_STACK (1);
10839                         MONO_INST_NEW (cfg, ins, *ip);
10840                         --sp;
10841                         CHECK_OPSIZE (5);
10842                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10843                         CHECK_TYPELOAD (klass);
10844                         mono_class_init (klass);
10845
10846                         context_used = mini_class_check_context_used (cfg, klass);
10847
10848                         // FIXME:
10849                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10850                         if (!src_var)
10851                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10852                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10853                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10854
10855                         if (context_used) {
10856                                 MonoInst *klass_ins;
10857
10858                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10859                                                 klass, MONO_RGCTX_INFO_KLASS);
10860
10861                                 // FIXME:
10862                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10863                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10864                         } else {
10865                                 mini_emit_class_check (cfg, klass_reg, klass);
10866                         }
10867                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10868                         ins->type = STACK_MP;
10869                         *sp++ = ins;
10870                         ip += 5;
10871                         break;
10872                 }
10873                 case CEE_MKREFANY: {
10874                         MonoInst *loc, *addr;
10875
10876                         GSHAREDVT_FAILURE (*ip);
10877
10878                         CHECK_STACK (1);
10879                         MONO_INST_NEW (cfg, ins, *ip);
10880                         --sp;
10881                         CHECK_OPSIZE (5);
10882                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10883                         CHECK_TYPELOAD (klass);
10884                         mono_class_init (klass);
10885
10886                         context_used = mini_class_check_context_used (cfg, klass);
10887
10888                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10889                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10890
10891                         if (context_used) {
10892                                 MonoInst *const_ins;
10893                                 int type_reg = alloc_preg (cfg);
10894
10895                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10896                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10897                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10898                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10899                         } else if (cfg->compile_aot) {
10900                                 int const_reg = alloc_preg (cfg);
10901                                 int type_reg = alloc_preg (cfg);
10902
10903                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10904                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10905                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10906                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10907                         } else {
10908                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10909                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10910                         }
10911                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10912
10913                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10914                         ins->type = STACK_VTYPE;
10915                         ins->klass = mono_defaults.typed_reference_class;
10916                         *sp++ = ins;
10917                         ip += 5;
10918                         break;
10919                 }
10920                 case CEE_LDTOKEN: {
10921                         gpointer handle;
10922                         MonoClass *handle_class;
10923
10924                         CHECK_STACK_OVF (1);
10925
10926                         CHECK_OPSIZE (5);
10927                         n = read32 (ip + 1);
10928
10929                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10930                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10931                                 handle = mono_method_get_wrapper_data (method, n);
10932                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10933                                 if (handle_class == mono_defaults.typehandle_class)
10934                                         handle = &((MonoClass*)handle)->byval_arg;
10935                         }
10936                         else {
10937                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10938                         }
10939                         if (!handle)
10940                                 LOAD_ERROR;
10941                         mono_class_init (handle_class);
10942                         if (cfg->generic_sharing_context) {
10943                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10944                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10945                                         /* This case handles ldtoken
10946                                            of an open type, like for
10947                                            typeof(Gen<>). */
10948                                         context_used = 0;
10949                                 } else if (handle_class == mono_defaults.typehandle_class) {
10950                                         /* If we get a MONO_TYPE_CLASS
10951                                            then we need to provide the
10952                                            open type, not an
10953                                            instantiation of it. */
10954                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10955                                                 context_used = 0;
10956                                         else
10957                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10958                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10959                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10960                                 else if (handle_class == mono_defaults.methodhandle_class)
10961                                         context_used = mini_method_check_context_used (cfg, handle);
10962                                 else
10963                                         g_assert_not_reached ();
10964                         }
10965
10966                         if ((cfg->opt & MONO_OPT_SHARED) &&
10967                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10968                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10969                                 MonoInst *addr, *vtvar, *iargs [3];
10970                                 int method_context_used;
10971
10972                                 method_context_used = mini_method_check_context_used (cfg, method);
10973
10974                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10975
10976                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10977                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10978                                 if (method_context_used) {
10979                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10980                                                 method, MONO_RGCTX_INFO_METHOD);
10981                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10982                                 } else {
10983                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10984                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10985                                 }
10986                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10987
10988                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10989
10990                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10991                         } else {
10992                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10993                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10994                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10995                                         (cmethod->klass == mono_defaults.systemtype_class) &&
10996                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10997                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10998
10999                                         mono_class_init (tclass);
11000                                         if (context_used) {
11001                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11002                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11003                                         } else if (cfg->compile_aot) {
11004                                                 if (method->wrapper_type) {
11005                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
11006                                                                 /* Special case for static synchronized wrappers */
11007                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11008                                                         } else {
11009                                                                 /* FIXME: n is not a normal token */
11010                                                                 DISABLE_AOT (cfg);
11011                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11012                                                         }
11013                                                 } else {
11014                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11015                                                 }
11016                                         } else {
11017                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11018                                         }
11019                                         ins->type = STACK_OBJ;
11020                                         ins->klass = cmethod->klass;
11021                                         ip += 5;
11022                                 } else {
11023                                         MonoInst *addr, *vtvar;
11024
11025                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11026
11027                                         if (context_used) {
11028                                                 if (handle_class == mono_defaults.typehandle_class) {
11029                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11030                                                                         mono_class_from_mono_type (handle),
11031                                                                         MONO_RGCTX_INFO_TYPE);
11032                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11033                                                         ins = emit_get_rgctx_method (cfg, context_used,
11034                                                                         handle, MONO_RGCTX_INFO_METHOD);
11035                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11036                                                         ins = emit_get_rgctx_field (cfg, context_used,
11037                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11038                                                 } else {
11039                                                         g_assert_not_reached ();
11040                                                 }
11041                                         } else if (cfg->compile_aot) {
11042                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11043                                         } else {
11044                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11045                                         }
11046                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11047                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11048                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11049                                 }
11050                         }
11051
11052                         *sp++ = ins;
11053                         ip += 5;
11054                         break;
11055                 }
11056                 case CEE_THROW:
11057                         CHECK_STACK (1);
11058                         MONO_INST_NEW (cfg, ins, OP_THROW);
11059                         --sp;
11060                         ins->sreg1 = sp [0]->dreg;
11061                         ip++;
11062                         bblock->out_of_line = TRUE;
11063                         MONO_ADD_INS (bblock, ins);
11064                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11065                         MONO_ADD_INS (bblock, ins);
11066                         sp = stack_start;
11067                         
11068                         link_bblock (cfg, bblock, end_bblock);
11069                         start_new_bblock = 1;
11070                         break;
11071                 case CEE_ENDFINALLY:
11072                         /* mono_save_seq_point_info () depends on this */
11073                         if (sp != stack_start)
11074                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11075                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11076                         MONO_ADD_INS (bblock, ins);
11077                         ip++;
11078                         start_new_bblock = 1;
11079
11080                         /*
11081                          * Control will leave the method so empty the stack, otherwise
11082                          * the next basic block will start with a nonempty stack.
11083                          */
11084                         while (sp != stack_start) {
11085                                 sp--;
11086                         }
11087                         break;
11088                 case CEE_LEAVE:
11089                 case CEE_LEAVE_S: {
11090                         GList *handlers;
11091
11092                         if (*ip == CEE_LEAVE) {
11093                                 CHECK_OPSIZE (5);
11094                                 target = ip + 5 + (gint32)read32(ip + 1);
11095                         } else {
11096                                 CHECK_OPSIZE (2);
11097                                 target = ip + 2 + (signed char)(ip [1]);
11098                         }
11099
11100                         /* empty the stack */
11101                         while (sp != stack_start) {
11102                                 sp--;
11103                         }
11104
11105                         /* 
11106                          * If this leave statement is in a catch block, check for a
11107                          * pending exception, and rethrow it if necessary.
11108                          * We avoid doing this in runtime invoke wrappers, since those are called
11109                          * by native code which excepts the wrapper to catch all exceptions.
11110                          */
11111                         for (i = 0; i < header->num_clauses; ++i) {
11112                                 MonoExceptionClause *clause = &header->clauses [i];
11113
11114                                 /* 
11115                                  * Use <= in the final comparison to handle clauses with multiple
11116                                  * leave statements, like in bug #78024.
11117                                  * The ordering of the exception clauses guarantees that we find the
11118                                  * innermost clause.
11119                                  */
11120                                 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) {
11121                                         MonoInst *exc_ins;
11122                                         MonoBasicBlock *dont_throw;
11123
11124                                         /*
11125                                           MonoInst *load;
11126
11127                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11128                                         */
11129
11130                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11131
11132                                         NEW_BBLOCK (cfg, dont_throw);
11133
11134                                         /*
11135                                          * Currently, we always rethrow the abort exception, despite the 
11136                                          * fact that this is not correct. See thread6.cs for an example. 
11137                                          * But propagating the abort exception is more important than 
11138                                          * getting the sematics right.
11139                                          */
11140                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11141                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11142                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11143
11144                                         MONO_START_BB (cfg, dont_throw);
11145                                         bblock = cfg->cbb;
11146                                 }
11147                         }
11148
11149                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11150                                 GList *tmp;
11151                                 MonoExceptionClause *clause;
11152
11153                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11154                                         clause = tmp->data;
11155                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11156                                         g_assert (tblock);
11157                                         link_bblock (cfg, bblock, tblock);
11158                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11159                                         ins->inst_target_bb = tblock;
11160                                         ins->inst_eh_block = clause;
11161                                         MONO_ADD_INS (bblock, ins);
11162                                         bblock->has_call_handler = 1;
11163                                         if (COMPILE_LLVM (cfg)) {
11164                                                 MonoBasicBlock *target_bb;
11165
11166                                                 /* 
11167                                                  * Link the finally bblock with the target, since it will
11168                                                  * conceptually branch there.
11169                                                  * FIXME: Have to link the bblock containing the endfinally.
11170                                                  */
11171                                                 GET_BBLOCK (cfg, target_bb, target);
11172                                                 link_bblock (cfg, tblock, target_bb);
11173                                         }
11174                                 }
11175                                 g_list_free (handlers);
11176                         } 
11177
11178                         MONO_INST_NEW (cfg, ins, OP_BR);
11179                         MONO_ADD_INS (bblock, ins);
11180                         GET_BBLOCK (cfg, tblock, target);
11181                         link_bblock (cfg, bblock, tblock);
11182                         ins->inst_target_bb = tblock;
11183                         start_new_bblock = 1;
11184
11185                         if (*ip == CEE_LEAVE)
11186                                 ip += 5;
11187                         else
11188                                 ip += 2;
11189
11190                         break;
11191                 }
11192
11193                         /*
11194                          * Mono specific opcodes
11195                          */
11196                 case MONO_CUSTOM_PREFIX: {
11197
11198                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11199
11200                         CHECK_OPSIZE (2);
11201                         switch (ip [1]) {
11202                         case CEE_MONO_ICALL: {
11203                                 gpointer func;
11204                                 MonoJitICallInfo *info;
11205
11206                                 token = read32 (ip + 2);
11207                                 func = mono_method_get_wrapper_data (method, token);
11208                                 info = mono_find_jit_icall_by_addr (func);
11209                                 if (!info)
11210                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11211                                 g_assert (info);
11212
11213                                 CHECK_STACK (info->sig->param_count);
11214                                 sp -= info->sig->param_count;
11215
11216                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11217                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11218                                         *sp++ = ins;
11219
11220                                 ip += 6;
11221                                 inline_costs += 10 * num_calls++;
11222
11223                                 break;
11224                         }
11225                         case CEE_MONO_LDPTR: {
11226                                 gpointer ptr;
11227
11228                                 CHECK_STACK_OVF (1);
11229                                 CHECK_OPSIZE (6);
11230                                 token = read32 (ip + 2);
11231
11232                                 ptr = mono_method_get_wrapper_data (method, token);
11233                                 /* FIXME: Generalize this */
11234                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11235                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11236                                         *sp++ = ins;
11237                                         ip += 6;
11238                                         break;
11239                                 }
11240                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11241                                 *sp++ = ins;
11242                                 ip += 6;
11243                                 inline_costs += 10 * num_calls++;
11244                                 /* Can't embed random pointers into AOT code */
11245                                 DISABLE_AOT (cfg);
11246                                 break;
11247                         }
11248                         case CEE_MONO_JIT_ICALL_ADDR: {
11249                                 MonoJitICallInfo *callinfo;
11250                                 gpointer ptr;
11251
11252                                 CHECK_STACK_OVF (1);
11253                                 CHECK_OPSIZE (6);
11254                                 token = read32 (ip + 2);
11255
11256                                 ptr = mono_method_get_wrapper_data (method, token);
11257                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11258                                 g_assert (callinfo);
11259                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11260                                 *sp++ = ins;
11261                                 ip += 6;
11262                                 inline_costs += 10 * num_calls++;
11263                                 break;
11264                         }
11265                         case CEE_MONO_ICALL_ADDR: {
11266                                 MonoMethod *cmethod;
11267                                 gpointer ptr;
11268
11269                                 CHECK_STACK_OVF (1);
11270                                 CHECK_OPSIZE (6);
11271                                 token = read32 (ip + 2);
11272
11273                                 cmethod = mono_method_get_wrapper_data (method, token);
11274
11275                                 if (cfg->compile_aot) {
11276                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11277                                 } else {
11278                                         ptr = mono_lookup_internal_call (cmethod);
11279                                         g_assert (ptr);
11280                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11281                                 }
11282                                 *sp++ = ins;
11283                                 ip += 6;
11284                                 break;
11285                         }
11286                         case CEE_MONO_VTADDR: {
11287                                 MonoInst *src_var, *src;
11288
11289                                 CHECK_STACK (1);
11290                                 --sp;
11291
11292                                 // FIXME:
11293                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11294                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11295                                 *sp++ = src;
11296                                 ip += 2;
11297                                 break;
11298                         }
11299                         case CEE_MONO_NEWOBJ: {
11300                                 MonoInst *iargs [2];
11301
11302                                 CHECK_STACK_OVF (1);
11303                                 CHECK_OPSIZE (6);
11304                                 token = read32 (ip + 2);
11305                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11306                                 mono_class_init (klass);
11307                                 NEW_DOMAINCONST (cfg, iargs [0]);
11308                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11309                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11310                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11311                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11312                                 ip += 6;
11313                                 inline_costs += 10 * num_calls++;
11314                                 break;
11315                         }
11316                         case CEE_MONO_OBJADDR:
11317                                 CHECK_STACK (1);
11318                                 --sp;
11319                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11320                                 ins->dreg = alloc_ireg_mp (cfg);
11321                                 ins->sreg1 = sp [0]->dreg;
11322                                 ins->type = STACK_MP;
11323                                 MONO_ADD_INS (cfg->cbb, ins);
11324                                 *sp++ = ins;
11325                                 ip += 2;
11326                                 break;
11327                         case CEE_MONO_LDNATIVEOBJ:
11328                                 /*
11329                                  * Similar to LDOBJ, but instead load the unmanaged 
11330                                  * representation of the vtype to the stack.
11331                                  */
11332                                 CHECK_STACK (1);
11333                                 CHECK_OPSIZE (6);
11334                                 --sp;
11335                                 token = read32 (ip + 2);
11336                                 klass = mono_method_get_wrapper_data (method, token);
11337                                 g_assert (klass->valuetype);
11338                                 mono_class_init (klass);
11339
11340                                 {
11341                                         MonoInst *src, *dest, *temp;
11342
11343                                         src = sp [0];
11344                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11345                                         temp->backend.is_pinvoke = 1;
11346                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11347                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11348
11349                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11350                                         dest->type = STACK_VTYPE;
11351                                         dest->klass = klass;
11352
11353                                         *sp ++ = dest;
11354                                         ip += 6;
11355                                 }
11356                                 break;
11357                         case CEE_MONO_RETOBJ: {
11358                                 /*
11359                                  * Same as RET, but return the native representation of a vtype
11360                                  * to the caller.
11361                                  */
11362                                 g_assert (cfg->ret);
11363                                 g_assert (mono_method_signature (method)->pinvoke); 
11364                                 CHECK_STACK (1);
11365                                 --sp;
11366                                 
11367                                 CHECK_OPSIZE (6);
11368                                 token = read32 (ip + 2);    
11369                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11370
11371                                 if (!cfg->vret_addr) {
11372                                         g_assert (cfg->ret_var_is_local);
11373
11374                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11375                                 } else {
11376                                         EMIT_NEW_RETLOADA (cfg, ins);
11377                                 }
11378                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11379                                 
11380                                 if (sp != stack_start)
11381                                         UNVERIFIED;
11382                                 
11383                                 MONO_INST_NEW (cfg, ins, OP_BR);
11384                                 ins->inst_target_bb = end_bblock;
11385                                 MONO_ADD_INS (bblock, ins);
11386                                 link_bblock (cfg, bblock, end_bblock);
11387                                 start_new_bblock = 1;
11388                                 ip += 6;
11389                                 break;
11390                         }
11391                         case CEE_MONO_CISINST:
11392                         case CEE_MONO_CCASTCLASS: {
11393                                 int token;
11394                                 CHECK_STACK (1);
11395                                 --sp;
11396                                 CHECK_OPSIZE (6);
11397                                 token = read32 (ip + 2);
11398                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11399                                 if (ip [1] == CEE_MONO_CISINST)
11400                                         ins = handle_cisinst (cfg, klass, sp [0]);
11401                                 else
11402                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11403                                 bblock = cfg->cbb;
11404                                 *sp++ = ins;
11405                                 ip += 6;
11406                                 break;
11407                         }
11408                         case CEE_MONO_SAVE_LMF:
11409                         case CEE_MONO_RESTORE_LMF:
11410 #ifdef MONO_ARCH_HAVE_LMF_OPS
11411                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11412                                 MONO_ADD_INS (bblock, ins);
11413                                 cfg->need_lmf_area = TRUE;
11414 #endif
11415                                 ip += 2;
11416                                 break;
11417                         case CEE_MONO_CLASSCONST:
11418                                 CHECK_STACK_OVF (1);
11419                                 CHECK_OPSIZE (6);
11420                                 token = read32 (ip + 2);
11421                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11422                                 *sp++ = ins;
11423                                 ip += 6;
11424                                 inline_costs += 10 * num_calls++;
11425                                 break;
11426                         case CEE_MONO_NOT_TAKEN:
11427                                 bblock->out_of_line = TRUE;
11428                                 ip += 2;
11429                                 break;
11430                         case CEE_MONO_TLS: {
11431                                 int key;
11432
11433                                 CHECK_STACK_OVF (1);
11434                                 CHECK_OPSIZE (6);
11435                                 key = (gint32)read32 (ip + 2);
11436                                 g_assert (key < TLS_KEY_NUM);
11437
11438                                 ins = mono_create_tls_get (cfg, key);
11439                                 if (!ins) {
11440                                         if (cfg->compile_aot) {
11441                                                 DISABLE_AOT (cfg);
11442                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11443                                                 ins->dreg = alloc_preg (cfg);
11444                                                 ins->type = STACK_PTR;
11445                                         } else {
11446                                                 g_assert_not_reached ();
11447                                         }
11448                                 }
11449                                 ins->type = STACK_PTR;
11450                                 MONO_ADD_INS (bblock, ins);
11451                                 *sp++ = ins;
11452                                 ip += 6;
11453                                 break;
11454                         }
11455                         case CEE_MONO_DYN_CALL: {
11456                                 MonoCallInst *call;
11457
11458                                 /* It would be easier to call a trampoline, but that would put an
11459                                  * extra frame on the stack, confusing exception handling. So
11460                                  * implement it inline using an opcode for now.
11461                                  */
11462
11463                                 if (!cfg->dyn_call_var) {
11464                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11465                                         /* prevent it from being register allocated */
11466                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11467                                 }
11468
11469                                 /* Has to use a call inst since it local regalloc expects it */
11470                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11471                                 ins = (MonoInst*)call;
11472                                 sp -= 2;
11473                                 ins->sreg1 = sp [0]->dreg;
11474                                 ins->sreg2 = sp [1]->dreg;
11475                                 MONO_ADD_INS (bblock, ins);
11476
11477                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11478
11479                                 ip += 2;
11480                                 inline_costs += 10 * num_calls++;
11481
11482                                 break;
11483                         }
11484                         case CEE_MONO_MEMORY_BARRIER: {
11485                                 CHECK_OPSIZE (5);
11486                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11487                                 ip += 5;
11488                                 break;
11489                         }
11490                         case CEE_MONO_JIT_ATTACH: {
11491                                 MonoInst *args [16];
11492                                 MonoInst *ad_ins, *lmf_ins;
11493                                 MonoBasicBlock *next_bb = NULL;
11494
11495                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11496
11497                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11498                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11499
11500 #if TARGET_WIN32
11501                                 ad_ins = NULL;
11502                                 lmf_ins = NULL;
11503 #else
11504                                 ad_ins = mono_get_domain_intrinsic (cfg);
11505                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11506 #endif
11507
11508                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11509                                         NEW_BBLOCK (cfg, next_bb);
11510
11511                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11512                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11513                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11514
11515                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11516                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11517                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11518                                 }
11519
11520                                 if (cfg->compile_aot) {
11521                                         /* AOT code is only used in the root domain */
11522                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11523                                 } else {
11524                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11525                                 }
11526                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11527                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11528
11529                                 if (next_bb) {
11530                                         MONO_START_BB (cfg, next_bb);
11531                                         bblock = cfg->cbb;
11532                                 }
11533                                 ip += 2;
11534                                 break;
11535                         }
11536                         case CEE_MONO_JIT_DETACH: {
11537                                 MonoInst *args [16];
11538
11539                                 /* Restore the original domain */
11540                                 dreg = alloc_ireg (cfg);
11541                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11542                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11543                                 ip += 2;
11544                                 break;
11545                         }
11546                         default:
11547                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11548                                 break;
11549                         }
11550                         break;
11551                 }
11552
11553                 case CEE_PREFIX1: {
11554                         CHECK_OPSIZE (2);
11555                         switch (ip [1]) {
11556                         case CEE_ARGLIST: {
11557                                 /* somewhat similar to LDTOKEN */
11558                                 MonoInst *addr, *vtvar;
11559                                 CHECK_STACK_OVF (1);
11560                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11561
11562                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11563                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11564
11565                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11566                                 ins->type = STACK_VTYPE;
11567                                 ins->klass = mono_defaults.argumenthandle_class;
11568                                 *sp++ = ins;
11569                                 ip += 2;
11570                                 break;
11571                         }
11572                         case CEE_CEQ:
11573                         case CEE_CGT:
11574                         case CEE_CGT_UN:
11575                         case CEE_CLT:
11576                         case CEE_CLT_UN: {
11577                                 MonoInst *cmp;
11578                                 CHECK_STACK (2);
11579                                 /*
11580                                  * The following transforms:
11581                                  *    CEE_CEQ    into OP_CEQ
11582                                  *    CEE_CGT    into OP_CGT
11583                                  *    CEE_CGT_UN into OP_CGT_UN
11584                                  *    CEE_CLT    into OP_CLT
11585                                  *    CEE_CLT_UN into OP_CLT_UN
11586                                  */
11587                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11588                                 
11589                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11590                                 sp -= 2;
11591                                 cmp->sreg1 = sp [0]->dreg;
11592                                 cmp->sreg2 = sp [1]->dreg;
11593                                 type_from_op (cmp, sp [0], sp [1]);
11594                                 CHECK_TYPE (cmp);
11595                                 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))))
11596                                         cmp->opcode = OP_LCOMPARE;
11597                                 else if (sp [0]->type == STACK_R8)
11598                                         cmp->opcode = OP_FCOMPARE;
11599                                 else
11600                                         cmp->opcode = OP_ICOMPARE;
11601                                 MONO_ADD_INS (bblock, cmp);
11602                                 ins->type = STACK_I4;
11603                                 ins->dreg = alloc_dreg (cfg, ins->type);
11604                                 type_from_op (ins, sp [0], sp [1]);
11605
11606                                 if (cmp->opcode == OP_FCOMPARE) {
11607                                         /*
11608                                          * The backends expect the fceq opcodes to do the
11609                                          * comparison too.
11610                                          */
11611                                         cmp->opcode = OP_NOP;
11612                                         ins->sreg1 = cmp->sreg1;
11613                                         ins->sreg2 = cmp->sreg2;
11614                                 }
11615                                 MONO_ADD_INS (bblock, ins);
11616                                 *sp++ = ins;
11617                                 ip += 2;
11618                                 break;
11619                         }
11620                         case CEE_LDFTN: {
11621                                 MonoInst *argconst;
11622                                 MonoMethod *cil_method;
11623
11624                                 CHECK_STACK_OVF (1);
11625                                 CHECK_OPSIZE (6);
11626                                 n = read32 (ip + 2);
11627                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11628                                 if (!cmethod || mono_loader_get_last_error ())
11629                                         LOAD_ERROR;
11630                                 mono_class_init (cmethod->klass);
11631
11632                                 mono_save_token_info (cfg, image, n, cmethod);
11633
11634                                 context_used = mini_method_check_context_used (cfg, cmethod);
11635
11636                                 cil_method = cmethod;
11637                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11638                                         METHOD_ACCESS_FAILURE;
11639
11640                                 if (mono_security_cas_enabled ()) {
11641                                         if (check_linkdemand (cfg, method, cmethod))
11642                                                 INLINE_FAILURE ("linkdemand");
11643                                         CHECK_CFG_EXCEPTION;
11644                                 } else if (mono_security_core_clr_enabled ()) {
11645                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11646                                 }
11647
11648                                 /* 
11649                                  * Optimize the common case of ldftn+delegate creation
11650                                  */
11651                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11652                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11653                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11654                                                 MonoInst *target_ins;
11655                                                 MonoMethod *invoke;
11656                                                 int invoke_context_used;
11657
11658                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11659                                                 if (!invoke || !mono_method_signature (invoke))
11660                                                         LOAD_ERROR;
11661
11662                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11663
11664                                                 target_ins = sp [-1];
11665
11666                                                 if (mono_security_core_clr_enabled ())
11667                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11668
11669                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11670                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11671                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11672                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11673                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11674                                                         }
11675                                                 }
11676
11677 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11678                                                 /* FIXME: SGEN support */
11679                                                 if (invoke_context_used == 0) {
11680                                                         ip += 6;
11681                                                         if (cfg->verbose_level > 3)
11682                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11683                                                         sp --;
11684                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11685                                                         CHECK_CFG_EXCEPTION;
11686                                                         ip += 5;                        
11687                                                         sp ++;
11688                                                         break;
11689                                                 }
11690 #endif
11691                                         }
11692                                 }
11693
11694                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11695                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11696                                 *sp++ = ins;
11697                                 
11698                                 ip += 6;
11699                                 inline_costs += 10 * num_calls++;
11700                                 break;
11701                         }
11702                         case CEE_LDVIRTFTN: {
11703                                 MonoInst *args [2];
11704
11705                                 CHECK_STACK (1);
11706                                 CHECK_OPSIZE (6);
11707                                 n = read32 (ip + 2);
11708                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11709                                 if (!cmethod || mono_loader_get_last_error ())
11710                                         LOAD_ERROR;
11711                                 mono_class_init (cmethod->klass);
11712  
11713                                 context_used = mini_method_check_context_used (cfg, cmethod);
11714
11715                                 if (mono_security_cas_enabled ()) {
11716                                         if (check_linkdemand (cfg, method, cmethod))
11717                                                 INLINE_FAILURE ("linkdemand");
11718                                         CHECK_CFG_EXCEPTION;
11719                                 } else if (mono_security_core_clr_enabled ()) {
11720                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11721                                 }
11722
11723                                 --sp;
11724                                 args [0] = *sp;
11725
11726                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11727                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11728
11729                                 if (context_used)
11730                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11731                                 else
11732                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11733
11734                                 ip += 6;
11735                                 inline_costs += 10 * num_calls++;
11736                                 break;
11737                         }
11738                         case CEE_LDARG:
11739                                 CHECK_STACK_OVF (1);
11740                                 CHECK_OPSIZE (4);
11741                                 n = read16 (ip + 2);
11742                                 CHECK_ARG (n);
11743                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11744                                 *sp++ = ins;
11745                                 ip += 4;
11746                                 break;
11747                         case CEE_LDARGA:
11748                                 CHECK_STACK_OVF (1);
11749                                 CHECK_OPSIZE (4);
11750                                 n = read16 (ip + 2);
11751                                 CHECK_ARG (n);
11752                                 NEW_ARGLOADA (cfg, ins, n);
11753                                 MONO_ADD_INS (cfg->cbb, ins);
11754                                 *sp++ = ins;
11755                                 ip += 4;
11756                                 break;
11757                         case CEE_STARG:
11758                                 CHECK_STACK (1);
11759                                 --sp;
11760                                 CHECK_OPSIZE (4);
11761                                 n = read16 (ip + 2);
11762                                 CHECK_ARG (n);
11763                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11764                                         UNVERIFIED;
11765                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11766                                 ip += 4;
11767                                 break;
11768                         case CEE_LDLOC:
11769                                 CHECK_STACK_OVF (1);
11770                                 CHECK_OPSIZE (4);
11771                                 n = read16 (ip + 2);
11772                                 CHECK_LOCAL (n);
11773                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11774                                 *sp++ = ins;
11775                                 ip += 4;
11776                                 break;
11777                         case CEE_LDLOCA: {
11778                                 unsigned char *tmp_ip;
11779                                 CHECK_STACK_OVF (1);
11780                                 CHECK_OPSIZE (4);
11781                                 n = read16 (ip + 2);
11782                                 CHECK_LOCAL (n);
11783
11784                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11785                                         ip = tmp_ip;
11786                                         inline_costs += 1;
11787                                         break;
11788                                 }                       
11789                                 
11790                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11791                                 *sp++ = ins;
11792                                 ip += 4;
11793                                 break;
11794                         }
11795                         case CEE_STLOC:
11796                                 CHECK_STACK (1);
11797                                 --sp;
11798                                 CHECK_OPSIZE (4);
11799                                 n = read16 (ip + 2);
11800                                 CHECK_LOCAL (n);
11801                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11802                                         UNVERIFIED;
11803                                 emit_stloc_ir (cfg, sp, header, n);
11804                                 ip += 4;
11805                                 inline_costs += 1;
11806                                 break;
11807                         case CEE_LOCALLOC:
11808                                 CHECK_STACK (1);
11809                                 --sp;
11810                                 if (sp != stack_start) 
11811                                         UNVERIFIED;
11812                                 if (cfg->method != method) 
11813                                         /* 
11814                                          * Inlining this into a loop in a parent could lead to 
11815                                          * stack overflows which is different behavior than the
11816                                          * non-inlined case, thus disable inlining in this case.
11817                                          */
11818                                         goto inline_failure;
11819
11820                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11821                                 ins->dreg = alloc_preg (cfg);
11822                                 ins->sreg1 = sp [0]->dreg;
11823                                 ins->type = STACK_PTR;
11824                                 MONO_ADD_INS (cfg->cbb, ins);
11825
11826                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11827                                 if (init_locals)
11828                                         ins->flags |= MONO_INST_INIT;
11829
11830                                 *sp++ = ins;
11831                                 ip += 2;
11832                                 break;
11833                         case CEE_ENDFILTER: {
11834                                 MonoExceptionClause *clause, *nearest;
11835                                 int cc, nearest_num;
11836
11837                                 CHECK_STACK (1);
11838                                 --sp;
11839                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11840                                         UNVERIFIED;
11841                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11842                                 ins->sreg1 = (*sp)->dreg;
11843                                 MONO_ADD_INS (bblock, ins);
11844                                 start_new_bblock = 1;
11845                                 ip += 2;
11846
11847                                 nearest = NULL;
11848                                 nearest_num = 0;
11849                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11850                                         clause = &header->clauses [cc];
11851                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11852                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11853                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11854                                                 nearest = clause;
11855                                                 nearest_num = cc;
11856                                         }
11857                                 }
11858                                 g_assert (nearest);
11859                                 if ((ip - header->code) != nearest->handler_offset)
11860                                         UNVERIFIED;
11861
11862                                 break;
11863                         }
11864                         case CEE_UNALIGNED_:
11865                                 ins_flag |= MONO_INST_UNALIGNED;
11866                                 /* FIXME: record alignment? we can assume 1 for now */
11867                                 CHECK_OPSIZE (3);
11868                                 ip += 3;
11869                                 break;
11870                         case CEE_VOLATILE_:
11871                                 ins_flag |= MONO_INST_VOLATILE;
11872                                 ip += 2;
11873                                 break;
11874                         case CEE_TAIL_:
11875                                 ins_flag   |= MONO_INST_TAILCALL;
11876                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11877                                 /* Can't inline tail calls at this time */
11878                                 inline_costs += 100000;
11879                                 ip += 2;
11880                                 break;
11881                         case CEE_INITOBJ:
11882                                 CHECK_STACK (1);
11883                                 --sp;
11884                                 CHECK_OPSIZE (6);
11885                                 token = read32 (ip + 2);
11886                                 klass = mini_get_class (method, token, generic_context);
11887                                 CHECK_TYPELOAD (klass);
11888                                 if (generic_class_is_reference_type (cfg, klass))
11889                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11890                                 else
11891                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11892                                 ip += 6;
11893                                 inline_costs += 1;
11894                                 break;
11895                         case CEE_CONSTRAINED_:
11896                                 CHECK_OPSIZE (6);
11897                                 token = read32 (ip + 2);
11898                                 constrained_call = mini_get_class (method, token, generic_context);
11899                                 CHECK_TYPELOAD (constrained_call);
11900                                 ip += 6;
11901                                 break;
11902                         case CEE_CPBLK:
11903                         case CEE_INITBLK: {
11904                                 MonoInst *iargs [3];
11905                                 CHECK_STACK (3);
11906                                 sp -= 3;
11907
11908                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11909                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11910                                 } 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)) {
11911                                         /* emit_memset only works when val == 0 */
11912                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11913                                 } else {
11914                                         iargs [0] = sp [0];
11915                                         iargs [1] = sp [1];
11916                                         iargs [2] = sp [2];
11917                                         if (ip [1] == CEE_CPBLK) {
11918                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11919                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11920                                         } else {
11921                                                 MonoMethod *memset_method = get_memset_method ();
11922                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11923                                         }
11924                                 }
11925                                 ip += 2;
11926                                 inline_costs += 1;
11927                                 break;
11928                         }
11929                         case CEE_NO_:
11930                                 CHECK_OPSIZE (3);
11931                                 if (ip [2] & 0x1)
11932                                         ins_flag |= MONO_INST_NOTYPECHECK;
11933                                 if (ip [2] & 0x2)
11934                                         ins_flag |= MONO_INST_NORANGECHECK;
11935                                 /* we ignore the no-nullcheck for now since we
11936                                  * really do it explicitly only when doing callvirt->call
11937                                  */
11938                                 ip += 3;
11939                                 break;
11940                         case CEE_RETHROW: {
11941                                 MonoInst *load;
11942                                 int handler_offset = -1;
11943
11944                                 for (i = 0; i < header->num_clauses; ++i) {
11945                                         MonoExceptionClause *clause = &header->clauses [i];
11946                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11947                                                 handler_offset = clause->handler_offset;
11948                                                 break;
11949                                         }
11950                                 }
11951
11952                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11953
11954                                 g_assert (handler_offset != -1);
11955
11956                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11957                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11958                                 ins->sreg1 = load->dreg;
11959                                 MONO_ADD_INS (bblock, ins);
11960
11961                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11962                                 MONO_ADD_INS (bblock, ins);
11963
11964                                 sp = stack_start;
11965                                 link_bblock (cfg, bblock, end_bblock);
11966                                 start_new_bblock = 1;
11967                                 ip += 2;
11968                                 break;
11969                         }
11970                         case CEE_SIZEOF: {
11971                                 guint32 val;
11972                                 int ialign;
11973
11974                                 GSHAREDVT_FAILURE (*ip);
11975
11976                                 CHECK_STACK_OVF (1);
11977                                 CHECK_OPSIZE (6);
11978                                 token = read32 (ip + 2);
11979                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11980                                         MonoType *type = mono_type_create_from_typespec (image, token);
11981                                         val = mono_type_size (type, &ialign);
11982                                 } else {
11983                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11984                                         CHECK_TYPELOAD (klass);
11985                                         mono_class_init (klass);
11986                                         val = mono_type_size (&klass->byval_arg, &ialign);
11987                                 }
11988                                 EMIT_NEW_ICONST (cfg, ins, val);
11989                                 *sp++= ins;
11990                                 ip += 6;
11991                                 break;
11992                         }
11993                         case CEE_REFANYTYPE: {
11994                                 MonoInst *src_var, *src;
11995
11996                                 GSHAREDVT_FAILURE (*ip);
11997
11998                                 CHECK_STACK (1);
11999                                 --sp;
12000
12001                                 // FIXME:
12002                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12003                                 if (!src_var)
12004                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12005                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12006                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
12007                                 *sp++ = ins;
12008                                 ip += 2;
12009                                 break;
12010                         }
12011                         case CEE_READONLY_:
12012                                 readonly = TRUE;
12013                                 ip += 2;
12014                                 break;
12015
12016                         case CEE_UNUSED56:
12017                         case CEE_UNUSED57:
12018                         case CEE_UNUSED70:
12019                         case CEE_UNUSED:
12020                         case CEE_UNUSED99:
12021                                 UNVERIFIED;
12022                                 
12023                         default:
12024                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12025                                 UNVERIFIED;
12026                         }
12027                         break;
12028                 }
12029                 case CEE_UNUSED58:
12030                 case CEE_UNUSED1:
12031                         UNVERIFIED;
12032
12033                 default:
12034                         g_warning ("opcode 0x%02x not handled", *ip);
12035                         UNVERIFIED;
12036                 }
12037         }
12038         if (start_new_bblock != 1)
12039                 UNVERIFIED;
12040
12041         bblock->cil_length = ip - bblock->cil_code;
12042         if (bblock->next_bb) {
12043                 /* This could already be set because of inlining, #693905 */
12044                 MonoBasicBlock *bb = bblock;
12045
12046                 while (bb->next_bb)
12047                         bb = bb->next_bb;
12048                 bb->next_bb = end_bblock;
12049         } else {
12050                 bblock->next_bb = end_bblock;
12051         }
12052
12053         if (cfg->method == method && cfg->domainvar) {
12054                 MonoInst *store;
12055                 MonoInst *get_domain;
12056
12057                 cfg->cbb = init_localsbb;
12058
12059                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12060                         MONO_ADD_INS (cfg->cbb, get_domain);
12061                 } else {
12062                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12063                 }
12064                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12065                 MONO_ADD_INS (cfg->cbb, store);
12066         }
12067
12068 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12069         if (cfg->compile_aot)
12070                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12071                 mono_get_got_var (cfg);
12072 #endif
12073
12074         if (cfg->method == method && cfg->got_var)
12075                 mono_emit_load_got_addr (cfg);
12076
12077         if (init_localsbb) {
12078                 cfg->cbb = init_localsbb;
12079                 cfg->ip = NULL;
12080                 for (i = 0; i < header->num_locals; ++i) {
12081                         emit_init_local (cfg, i, header->locals [i], init_locals);
12082                 }
12083         }
12084
12085         if (cfg->init_ref_vars && cfg->method == method) {
12086                 /* Emit initialization for ref vars */
12087                 // FIXME: Avoid duplication initialization for IL locals.
12088                 for (i = 0; i < cfg->num_varinfo; ++i) {
12089                         MonoInst *ins = cfg->varinfo [i];
12090
12091                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12092                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12093                 }
12094         }
12095
12096         if (cfg->lmf_var && cfg->method == method) {
12097                 cfg->cbb = init_localsbb;
12098                 emit_push_lmf (cfg);
12099         }
12100
12101         if (seq_points) {
12102                 MonoBasicBlock *bb;
12103
12104                 /*
12105                  * Make seq points at backward branch targets interruptable.
12106                  */
12107                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12108                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12109                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12110         }
12111
12112         /* Add a sequence point for method entry/exit events */
12113         if (seq_points) {
12114                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12115                 MONO_ADD_INS (init_localsbb, ins);
12116                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12117                 MONO_ADD_INS (cfg->bb_exit, ins);
12118         }
12119
12120         /*
12121          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12122          * the code they refer to was dead (#11880).
12123          */
12124         if (sym_seq_points) {
12125                 for (i = 0; i < header->code_size; ++i) {
12126                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12127                                 MonoInst *ins;
12128
12129                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12130                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12131                         }
12132                 }
12133         }
12134
12135         cfg->ip = NULL;
12136
12137         if (cfg->method == method) {
12138                 MonoBasicBlock *bb;
12139                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12140                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12141                         if (cfg->spvars)
12142                                 mono_create_spvar_for_region (cfg, bb->region);
12143                         if (cfg->verbose_level > 2)
12144                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12145                 }
12146         }
12147
12148         g_slist_free (class_inits);
12149         dont_inline = g_list_remove (dont_inline, method);
12150
12151         if (inline_costs < 0) {
12152                 char *mname;
12153
12154                 /* Method is too large */
12155                 mname = mono_method_full_name (method, TRUE);
12156                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12157                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12158                 g_free (mname);
12159                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12160                 mono_basic_block_free (original_bb);
12161                 return -1;
12162         }
12163
12164         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12165                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12166
12167         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12168         mono_basic_block_free (original_bb);
12169         return inline_costs;
12170  
12171  exception_exit:
12172         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12173         goto cleanup;
12174
12175  inline_failure:
12176         goto cleanup;
12177
12178  load_error:
12179         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
12180         goto cleanup;
12181
12182  unverified:
12183         set_exception_type_from_invalid_il (cfg, method, ip);
12184         goto cleanup;
12185
12186  cleanup:
12187         g_slist_free (class_inits);
12188         mono_basic_block_free (original_bb);
12189         dont_inline = g_list_remove (dont_inline, method);
12190         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12191         return -1;
12192 }
12193
12194 static int
12195 store_membase_reg_to_store_membase_imm (int opcode)
12196 {
12197         switch (opcode) {
12198         case OP_STORE_MEMBASE_REG:
12199                 return OP_STORE_MEMBASE_IMM;
12200         case OP_STOREI1_MEMBASE_REG:
12201                 return OP_STOREI1_MEMBASE_IMM;
12202         case OP_STOREI2_MEMBASE_REG:
12203                 return OP_STOREI2_MEMBASE_IMM;
12204         case OP_STOREI4_MEMBASE_REG:
12205                 return OP_STOREI4_MEMBASE_IMM;
12206         case OP_STOREI8_MEMBASE_REG:
12207                 return OP_STOREI8_MEMBASE_IMM;
12208         default:
12209                 g_assert_not_reached ();
12210         }
12211
12212         return -1;
12213 }               
12214
12215 int
12216 mono_op_to_op_imm (int opcode)
12217 {
12218         switch (opcode) {
12219         case OP_IADD:
12220                 return OP_IADD_IMM;
12221         case OP_ISUB:
12222                 return OP_ISUB_IMM;
12223         case OP_IDIV:
12224                 return OP_IDIV_IMM;
12225         case OP_IDIV_UN:
12226                 return OP_IDIV_UN_IMM;
12227         case OP_IREM:
12228                 return OP_IREM_IMM;
12229         case OP_IREM_UN:
12230                 return OP_IREM_UN_IMM;
12231         case OP_IMUL:
12232                 return OP_IMUL_IMM;
12233         case OP_IAND:
12234                 return OP_IAND_IMM;
12235         case OP_IOR:
12236                 return OP_IOR_IMM;
12237         case OP_IXOR:
12238                 return OP_IXOR_IMM;
12239         case OP_ISHL:
12240                 return OP_ISHL_IMM;
12241         case OP_ISHR:
12242                 return OP_ISHR_IMM;
12243         case OP_ISHR_UN:
12244                 return OP_ISHR_UN_IMM;
12245
12246         case OP_LADD:
12247                 return OP_LADD_IMM;
12248         case OP_LSUB:
12249                 return OP_LSUB_IMM;
12250         case OP_LAND:
12251                 return OP_LAND_IMM;
12252         case OP_LOR:
12253                 return OP_LOR_IMM;
12254         case OP_LXOR:
12255                 return OP_LXOR_IMM;
12256         case OP_LSHL:
12257                 return OP_LSHL_IMM;
12258         case OP_LSHR:
12259                 return OP_LSHR_IMM;
12260         case OP_LSHR_UN:
12261                 return OP_LSHR_UN_IMM;          
12262
12263         case OP_COMPARE:
12264                 return OP_COMPARE_IMM;
12265         case OP_ICOMPARE:
12266                 return OP_ICOMPARE_IMM;
12267         case OP_LCOMPARE:
12268                 return OP_LCOMPARE_IMM;
12269
12270         case OP_STORE_MEMBASE_REG:
12271                 return OP_STORE_MEMBASE_IMM;
12272         case OP_STOREI1_MEMBASE_REG:
12273                 return OP_STOREI1_MEMBASE_IMM;
12274         case OP_STOREI2_MEMBASE_REG:
12275                 return OP_STOREI2_MEMBASE_IMM;
12276         case OP_STOREI4_MEMBASE_REG:
12277                 return OP_STOREI4_MEMBASE_IMM;
12278
12279 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12280         case OP_X86_PUSH:
12281                 return OP_X86_PUSH_IMM;
12282         case OP_X86_COMPARE_MEMBASE_REG:
12283                 return OP_X86_COMPARE_MEMBASE_IMM;
12284 #endif
12285 #if defined(TARGET_AMD64)
12286         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12287                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12288 #endif
12289         case OP_VOIDCALL_REG:
12290                 return OP_VOIDCALL;
12291         case OP_CALL_REG:
12292                 return OP_CALL;
12293         case OP_LCALL_REG:
12294                 return OP_LCALL;
12295         case OP_FCALL_REG:
12296                 return OP_FCALL;
12297         case OP_LOCALLOC:
12298                 return OP_LOCALLOC_IMM;
12299         }
12300
12301         return -1;
12302 }
12303
12304 static int
12305 ldind_to_load_membase (int opcode)
12306 {
12307         switch (opcode) {
12308         case CEE_LDIND_I1:
12309                 return OP_LOADI1_MEMBASE;
12310         case CEE_LDIND_U1:
12311                 return OP_LOADU1_MEMBASE;
12312         case CEE_LDIND_I2:
12313                 return OP_LOADI2_MEMBASE;
12314         case CEE_LDIND_U2:
12315                 return OP_LOADU2_MEMBASE;
12316         case CEE_LDIND_I4:
12317                 return OP_LOADI4_MEMBASE;
12318         case CEE_LDIND_U4:
12319                 return OP_LOADU4_MEMBASE;
12320         case CEE_LDIND_I:
12321                 return OP_LOAD_MEMBASE;
12322         case CEE_LDIND_REF:
12323                 return OP_LOAD_MEMBASE;
12324         case CEE_LDIND_I8:
12325                 return OP_LOADI8_MEMBASE;
12326         case CEE_LDIND_R4:
12327                 return OP_LOADR4_MEMBASE;
12328         case CEE_LDIND_R8:
12329                 return OP_LOADR8_MEMBASE;
12330         default:
12331                 g_assert_not_reached ();
12332         }
12333
12334         return -1;
12335 }
12336
12337 static int
12338 stind_to_store_membase (int opcode)
12339 {
12340         switch (opcode) {
12341         case CEE_STIND_I1:
12342                 return OP_STOREI1_MEMBASE_REG;
12343         case CEE_STIND_I2:
12344                 return OP_STOREI2_MEMBASE_REG;
12345         case CEE_STIND_I4:
12346                 return OP_STOREI4_MEMBASE_REG;
12347         case CEE_STIND_I:
12348         case CEE_STIND_REF:
12349                 return OP_STORE_MEMBASE_REG;
12350         case CEE_STIND_I8:
12351                 return OP_STOREI8_MEMBASE_REG;
12352         case CEE_STIND_R4:
12353                 return OP_STORER4_MEMBASE_REG;
12354         case CEE_STIND_R8:
12355                 return OP_STORER8_MEMBASE_REG;
12356         default:
12357                 g_assert_not_reached ();
12358         }
12359
12360         return -1;
12361 }
12362
12363 int
12364 mono_load_membase_to_load_mem (int opcode)
12365 {
12366         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12367 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12368         switch (opcode) {
12369         case OP_LOAD_MEMBASE:
12370                 return OP_LOAD_MEM;
12371         case OP_LOADU1_MEMBASE:
12372                 return OP_LOADU1_MEM;
12373         case OP_LOADU2_MEMBASE:
12374                 return OP_LOADU2_MEM;
12375         case OP_LOADI4_MEMBASE:
12376                 return OP_LOADI4_MEM;
12377         case OP_LOADU4_MEMBASE:
12378                 return OP_LOADU4_MEM;
12379 #if SIZEOF_REGISTER == 8
12380         case OP_LOADI8_MEMBASE:
12381                 return OP_LOADI8_MEM;
12382 #endif
12383         }
12384 #endif
12385
12386         return -1;
12387 }
12388
12389 static inline int
12390 op_to_op_dest_membase (int store_opcode, int opcode)
12391 {
12392 #if defined(TARGET_X86)
12393         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12394                 return -1;
12395
12396         switch (opcode) {
12397         case OP_IADD:
12398                 return OP_X86_ADD_MEMBASE_REG;
12399         case OP_ISUB:
12400                 return OP_X86_SUB_MEMBASE_REG;
12401         case OP_IAND:
12402                 return OP_X86_AND_MEMBASE_REG;
12403         case OP_IOR:
12404                 return OP_X86_OR_MEMBASE_REG;
12405         case OP_IXOR:
12406                 return OP_X86_XOR_MEMBASE_REG;
12407         case OP_ADD_IMM:
12408         case OP_IADD_IMM:
12409                 return OP_X86_ADD_MEMBASE_IMM;
12410         case OP_SUB_IMM:
12411         case OP_ISUB_IMM:
12412                 return OP_X86_SUB_MEMBASE_IMM;
12413         case OP_AND_IMM:
12414         case OP_IAND_IMM:
12415                 return OP_X86_AND_MEMBASE_IMM;
12416         case OP_OR_IMM:
12417         case OP_IOR_IMM:
12418                 return OP_X86_OR_MEMBASE_IMM;
12419         case OP_XOR_IMM:
12420         case OP_IXOR_IMM:
12421                 return OP_X86_XOR_MEMBASE_IMM;
12422         case OP_MOVE:
12423                 return OP_NOP;
12424         }
12425 #endif
12426
12427 #if defined(TARGET_AMD64)
12428         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12429                 return -1;
12430
12431         switch (opcode) {
12432         case OP_IADD:
12433                 return OP_X86_ADD_MEMBASE_REG;
12434         case OP_ISUB:
12435                 return OP_X86_SUB_MEMBASE_REG;
12436         case OP_IAND:
12437                 return OP_X86_AND_MEMBASE_REG;
12438         case OP_IOR:
12439                 return OP_X86_OR_MEMBASE_REG;
12440         case OP_IXOR:
12441                 return OP_X86_XOR_MEMBASE_REG;
12442         case OP_IADD_IMM:
12443                 return OP_X86_ADD_MEMBASE_IMM;
12444         case OP_ISUB_IMM:
12445                 return OP_X86_SUB_MEMBASE_IMM;
12446         case OP_IAND_IMM:
12447                 return OP_X86_AND_MEMBASE_IMM;
12448         case OP_IOR_IMM:
12449                 return OP_X86_OR_MEMBASE_IMM;
12450         case OP_IXOR_IMM:
12451                 return OP_X86_XOR_MEMBASE_IMM;
12452         case OP_LADD:
12453                 return OP_AMD64_ADD_MEMBASE_REG;
12454         case OP_LSUB:
12455                 return OP_AMD64_SUB_MEMBASE_REG;
12456         case OP_LAND:
12457                 return OP_AMD64_AND_MEMBASE_REG;
12458         case OP_LOR:
12459                 return OP_AMD64_OR_MEMBASE_REG;
12460         case OP_LXOR:
12461                 return OP_AMD64_XOR_MEMBASE_REG;
12462         case OP_ADD_IMM:
12463         case OP_LADD_IMM:
12464                 return OP_AMD64_ADD_MEMBASE_IMM;
12465         case OP_SUB_IMM:
12466         case OP_LSUB_IMM:
12467                 return OP_AMD64_SUB_MEMBASE_IMM;
12468         case OP_AND_IMM:
12469         case OP_LAND_IMM:
12470                 return OP_AMD64_AND_MEMBASE_IMM;
12471         case OP_OR_IMM:
12472         case OP_LOR_IMM:
12473                 return OP_AMD64_OR_MEMBASE_IMM;
12474         case OP_XOR_IMM:
12475         case OP_LXOR_IMM:
12476                 return OP_AMD64_XOR_MEMBASE_IMM;
12477         case OP_MOVE:
12478                 return OP_NOP;
12479         }
12480 #endif
12481
12482         return -1;
12483 }
12484
12485 static inline int
12486 op_to_op_store_membase (int store_opcode, int opcode)
12487 {
12488 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12489         switch (opcode) {
12490         case OP_ICEQ:
12491                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12492                         return OP_X86_SETEQ_MEMBASE;
12493         case OP_CNE:
12494                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12495                         return OP_X86_SETNE_MEMBASE;
12496         }
12497 #endif
12498
12499         return -1;
12500 }
12501
12502 static inline int
12503 op_to_op_src1_membase (int load_opcode, int opcode)
12504 {
12505 #ifdef TARGET_X86
12506         /* FIXME: This has sign extension issues */
12507         /*
12508         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12509                 return OP_X86_COMPARE_MEMBASE8_IMM;
12510         */
12511
12512         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12513                 return -1;
12514
12515         switch (opcode) {
12516         case OP_X86_PUSH:
12517                 return OP_X86_PUSH_MEMBASE;
12518         case OP_COMPARE_IMM:
12519         case OP_ICOMPARE_IMM:
12520                 return OP_X86_COMPARE_MEMBASE_IMM;
12521         case OP_COMPARE:
12522         case OP_ICOMPARE:
12523                 return OP_X86_COMPARE_MEMBASE_REG;
12524         }
12525 #endif
12526
12527 #ifdef TARGET_AMD64
12528         /* FIXME: This has sign extension issues */
12529         /*
12530         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12531                 return OP_X86_COMPARE_MEMBASE8_IMM;
12532         */
12533
12534         switch (opcode) {
12535         case OP_X86_PUSH:
12536 #ifdef __mono_ilp32__
12537                 if (load_opcode == OP_LOADI8_MEMBASE)
12538 #else
12539                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12540 #endif
12541                         return OP_X86_PUSH_MEMBASE;
12542                 break;
12543                 /* FIXME: This only works for 32 bit immediates
12544         case OP_COMPARE_IMM:
12545         case OP_LCOMPARE_IMM:
12546                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12547                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12548                 */
12549         case OP_ICOMPARE_IMM:
12550                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12551                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12552                 break;
12553         case OP_COMPARE:
12554         case OP_LCOMPARE:
12555 #ifdef __mono_ilp32__
12556                 if (load_opcode == OP_LOAD_MEMBASE)
12557                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12558                 if (load_opcode == OP_LOADI8_MEMBASE)
12559 #else
12560                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12561 #endif
12562                         return OP_AMD64_COMPARE_MEMBASE_REG;
12563                 break;
12564         case OP_ICOMPARE:
12565                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12566                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12567                 break;
12568         }
12569 #endif
12570
12571         return -1;
12572 }
12573
12574 static inline int
12575 op_to_op_src2_membase (int load_opcode, int opcode)
12576 {
12577 #ifdef TARGET_X86
12578         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12579                 return -1;
12580         
12581         switch (opcode) {
12582         case OP_COMPARE:
12583         case OP_ICOMPARE:
12584                 return OP_X86_COMPARE_REG_MEMBASE;
12585         case OP_IADD:
12586                 return OP_X86_ADD_REG_MEMBASE;
12587         case OP_ISUB:
12588                 return OP_X86_SUB_REG_MEMBASE;
12589         case OP_IAND:
12590                 return OP_X86_AND_REG_MEMBASE;
12591         case OP_IOR:
12592                 return OP_X86_OR_REG_MEMBASE;
12593         case OP_IXOR:
12594                 return OP_X86_XOR_REG_MEMBASE;
12595         }
12596 #endif
12597
12598 #ifdef TARGET_AMD64
12599 #ifdef __mono_ilp32__
12600         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12601 #else
12602         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12603 #endif
12604                 switch (opcode) {
12605                 case OP_ICOMPARE:
12606                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12607                 case OP_IADD:
12608                         return OP_X86_ADD_REG_MEMBASE;
12609                 case OP_ISUB:
12610                         return OP_X86_SUB_REG_MEMBASE;
12611                 case OP_IAND:
12612                         return OP_X86_AND_REG_MEMBASE;
12613                 case OP_IOR:
12614                         return OP_X86_OR_REG_MEMBASE;
12615                 case OP_IXOR:
12616                         return OP_X86_XOR_REG_MEMBASE;
12617                 }
12618 #ifdef __mono_ilp32__
12619         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12620 #else
12621         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12622 #endif
12623                 switch (opcode) {
12624                 case OP_COMPARE:
12625                 case OP_LCOMPARE:
12626                         return OP_AMD64_COMPARE_REG_MEMBASE;
12627                 case OP_LADD:
12628                         return OP_AMD64_ADD_REG_MEMBASE;
12629                 case OP_LSUB:
12630                         return OP_AMD64_SUB_REG_MEMBASE;
12631                 case OP_LAND:
12632                         return OP_AMD64_AND_REG_MEMBASE;
12633                 case OP_LOR:
12634                         return OP_AMD64_OR_REG_MEMBASE;
12635                 case OP_LXOR:
12636                         return OP_AMD64_XOR_REG_MEMBASE;
12637                 }
12638         }
12639 #endif
12640
12641         return -1;
12642 }
12643
12644 int
12645 mono_op_to_op_imm_noemul (int opcode)
12646 {
12647         switch (opcode) {
12648 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12649         case OP_LSHR:
12650         case OP_LSHL:
12651         case OP_LSHR_UN:
12652                 return -1;
12653 #endif
12654 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12655         case OP_IDIV:
12656         case OP_IDIV_UN:
12657         case OP_IREM:
12658         case OP_IREM_UN:
12659                 return -1;
12660 #endif
12661 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12662         case OP_IMUL:
12663                 return -1;
12664 #endif
12665         default:
12666                 return mono_op_to_op_imm (opcode);
12667         }
12668 }
12669
12670 /**
12671  * mono_handle_global_vregs:
12672  *
12673  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12674  * for them.
12675  */
12676 void
12677 mono_handle_global_vregs (MonoCompile *cfg)
12678 {
12679         gint32 *vreg_to_bb;
12680         MonoBasicBlock *bb;
12681         int i, pos;
12682
12683         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12684
12685 #ifdef MONO_ARCH_SIMD_INTRINSICS
12686         if (cfg->uses_simd_intrinsics)
12687                 mono_simd_simplify_indirection (cfg);
12688 #endif
12689
12690         /* Find local vregs used in more than one bb */
12691         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12692                 MonoInst *ins = bb->code;       
12693                 int block_num = bb->block_num;
12694
12695                 if (cfg->verbose_level > 2)
12696                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12697
12698                 cfg->cbb = bb;
12699                 for (; ins; ins = ins->next) {
12700                         const char *spec = INS_INFO (ins->opcode);
12701                         int regtype = 0, regindex;
12702                         gint32 prev_bb;
12703
12704                         if (G_UNLIKELY (cfg->verbose_level > 2))
12705                                 mono_print_ins (ins);
12706
12707                         g_assert (ins->opcode >= MONO_CEE_LAST);
12708
12709                         for (regindex = 0; regindex < 4; regindex ++) {
12710                                 int vreg = 0;
12711
12712                                 if (regindex == 0) {
12713                                         regtype = spec [MONO_INST_DEST];
12714                                         if (regtype == ' ')
12715                                                 continue;
12716                                         vreg = ins->dreg;
12717                                 } else if (regindex == 1) {
12718                                         regtype = spec [MONO_INST_SRC1];
12719                                         if (regtype == ' ')
12720                                                 continue;
12721                                         vreg = ins->sreg1;
12722                                 } else if (regindex == 2) {
12723                                         regtype = spec [MONO_INST_SRC2];
12724                                         if (regtype == ' ')
12725                                                 continue;
12726                                         vreg = ins->sreg2;
12727                                 } else if (regindex == 3) {
12728                                         regtype = spec [MONO_INST_SRC3];
12729                                         if (regtype == ' ')
12730                                                 continue;
12731                                         vreg = ins->sreg3;
12732                                 }
12733
12734 #if SIZEOF_REGISTER == 4
12735                                 /* In the LLVM case, the long opcodes are not decomposed */
12736                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12737                                         /*
12738                                          * Since some instructions reference the original long vreg,
12739                                          * and some reference the two component vregs, it is quite hard
12740                                          * to determine when it needs to be global. So be conservative.
12741                                          */
12742                                         if (!get_vreg_to_inst (cfg, vreg)) {
12743                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12744
12745                                                 if (cfg->verbose_level > 2)
12746                                                         printf ("LONG VREG R%d made global.\n", vreg);
12747                                         }
12748
12749                                         /*
12750                                          * Make the component vregs volatile since the optimizations can
12751                                          * get confused otherwise.
12752                                          */
12753                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12754                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12755                                 }
12756 #endif
12757
12758                                 g_assert (vreg != -1);
12759
12760                                 prev_bb = vreg_to_bb [vreg];
12761                                 if (prev_bb == 0) {
12762                                         /* 0 is a valid block num */
12763                                         vreg_to_bb [vreg] = block_num + 1;
12764                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12765                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12766                                                 continue;
12767
12768                                         if (!get_vreg_to_inst (cfg, vreg)) {
12769                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12770                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12771
12772                                                 switch (regtype) {
12773                                                 case 'i':
12774                                                         if (vreg_is_ref (cfg, vreg))
12775                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12776                                                         else
12777                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12778                                                         break;
12779                                                 case 'l':
12780                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12781                                                         break;
12782                                                 case 'f':
12783                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12784                                                         break;
12785                                                 case 'v':
12786                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12787                                                         break;
12788                                                 default:
12789                                                         g_assert_not_reached ();
12790                                                 }
12791                                         }
12792
12793                                         /* Flag as having been used in more than one bb */
12794                                         vreg_to_bb [vreg] = -1;
12795                                 }
12796                         }
12797                 }
12798         }
12799
12800         /* If a variable is used in only one bblock, convert it into a local vreg */
12801         for (i = 0; i < cfg->num_varinfo; i++) {
12802                 MonoInst *var = cfg->varinfo [i];
12803                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12804
12805                 switch (var->type) {
12806                 case STACK_I4:
12807                 case STACK_OBJ:
12808                 case STACK_PTR:
12809                 case STACK_MP:
12810                 case STACK_VTYPE:
12811 #if SIZEOF_REGISTER == 8
12812                 case STACK_I8:
12813 #endif
12814 #if !defined(TARGET_X86)
12815                 /* Enabling this screws up the fp stack on x86 */
12816                 case STACK_R8:
12817 #endif
12818                         if (mono_arch_is_soft_float ())
12819                                 break;
12820
12821                         /* Arguments are implicitly global */
12822                         /* Putting R4 vars into registers doesn't work currently */
12823                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12824                         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) {
12825                                 /* 
12826                                  * Make that the variable's liveness interval doesn't contain a call, since
12827                                  * that would cause the lvreg to be spilled, making the whole optimization
12828                                  * useless.
12829                                  */
12830                                 /* This is too slow for JIT compilation */
12831 #if 0
12832                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12833                                         MonoInst *ins;
12834                                         int def_index, call_index, ins_index;
12835                                         gboolean spilled = FALSE;
12836
12837                                         def_index = -1;
12838                                         call_index = -1;
12839                                         ins_index = 0;
12840                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12841                                                 const char *spec = INS_INFO (ins->opcode);
12842
12843                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12844                                                         def_index = ins_index;
12845
12846                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12847                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12848                                                         if (call_index > def_index) {
12849                                                                 spilled = TRUE;
12850                                                                 break;
12851                                                         }
12852                                                 }
12853
12854                                                 if (MONO_IS_CALL (ins))
12855                                                         call_index = ins_index;
12856
12857                                                 ins_index ++;
12858                                         }
12859
12860                                         if (spilled)
12861                                                 break;
12862                                 }
12863 #endif
12864
12865                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12866                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12867                                 var->flags |= MONO_INST_IS_DEAD;
12868                                 cfg->vreg_to_inst [var->dreg] = NULL;
12869                         }
12870                         break;
12871                 }
12872         }
12873
12874         /* 
12875          * Compress the varinfo and vars tables so the liveness computation is faster and
12876          * takes up less space.
12877          */
12878         pos = 0;
12879         for (i = 0; i < cfg->num_varinfo; ++i) {
12880                 MonoInst *var = cfg->varinfo [i];
12881                 if (pos < i && cfg->locals_start == i)
12882                         cfg->locals_start = pos;
12883                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12884                         if (pos < i) {
12885                                 cfg->varinfo [pos] = cfg->varinfo [i];
12886                                 cfg->varinfo [pos]->inst_c0 = pos;
12887                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12888                                 cfg->vars [pos].idx = pos;
12889 #if SIZEOF_REGISTER == 4
12890                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12891                                         /* Modify the two component vars too */
12892                                         MonoInst *var1;
12893
12894                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12895                                         var1->inst_c0 = pos;
12896                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12897                                         var1->inst_c0 = pos;
12898                                 }
12899 #endif
12900                         }
12901                         pos ++;
12902                 }
12903         }
12904         cfg->num_varinfo = pos;
12905         if (cfg->locals_start > cfg->num_varinfo)
12906                 cfg->locals_start = cfg->num_varinfo;
12907 }
12908
12909 /**
12910  * mono_spill_global_vars:
12911  *
12912  *   Generate spill code for variables which are not allocated to registers, 
12913  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12914  * code is generated which could be optimized by the local optimization passes.
12915  */
12916 void
12917 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12918 {
12919         MonoBasicBlock *bb;
12920         char spec2 [16];
12921         int orig_next_vreg;
12922         guint32 *vreg_to_lvreg;
12923         guint32 *lvregs;
12924         guint32 i, lvregs_len;
12925         gboolean dest_has_lvreg = FALSE;
12926         guint32 stacktypes [128];
12927         MonoInst **live_range_start, **live_range_end;
12928         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12929         int *gsharedvt_vreg_to_idx = NULL;
12930
12931         *need_local_opts = FALSE;
12932
12933         memset (spec2, 0, sizeof (spec2));
12934
12935         /* FIXME: Move this function to mini.c */
12936         stacktypes ['i'] = STACK_PTR;
12937         stacktypes ['l'] = STACK_I8;
12938         stacktypes ['f'] = STACK_R8;
12939 #ifdef MONO_ARCH_SIMD_INTRINSICS
12940         stacktypes ['x'] = STACK_VTYPE;
12941 #endif
12942
12943 #if SIZEOF_REGISTER == 4
12944         /* Create MonoInsts for longs */
12945         for (i = 0; i < cfg->num_varinfo; i++) {
12946                 MonoInst *ins = cfg->varinfo [i];
12947
12948                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12949                         switch (ins->type) {
12950                         case STACK_R8:
12951                         case STACK_I8: {
12952                                 MonoInst *tree;
12953
12954                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12955                                         break;
12956
12957                                 g_assert (ins->opcode == OP_REGOFFSET);
12958
12959                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12960                                 g_assert (tree);
12961                                 tree->opcode = OP_REGOFFSET;
12962                                 tree->inst_basereg = ins->inst_basereg;
12963                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12964
12965                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12966                                 g_assert (tree);
12967                                 tree->opcode = OP_REGOFFSET;
12968                                 tree->inst_basereg = ins->inst_basereg;
12969                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12970                                 break;
12971                         }
12972                         default:
12973                                 break;
12974                         }
12975                 }
12976         }
12977 #endif
12978
12979         if (cfg->compute_gc_maps) {
12980                 /* registers need liveness info even for !non refs */
12981                 for (i = 0; i < cfg->num_varinfo; i++) {
12982                         MonoInst *ins = cfg->varinfo [i];
12983
12984                         if (ins->opcode == OP_REGVAR)
12985                                 ins->flags |= MONO_INST_GC_TRACK;
12986                 }
12987         }
12988
12989         if (cfg->gsharedvt) {
12990                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
12991
12992                 for (i = 0; i < cfg->num_varinfo; ++i) {
12993                         MonoInst *ins = cfg->varinfo [i];
12994                         int idx;
12995
12996                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12997                                 if (i >= cfg->locals_start) {
12998                                         /* Local */
12999                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13000                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13001                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13002                                         ins->inst_imm = idx;
13003                                 } else {
13004                                         /* Arg */
13005                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13006                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13007                                 }
13008                         }
13009                 }
13010         }
13011                 
13012         /* FIXME: widening and truncation */
13013
13014         /*
13015          * As an optimization, when a variable allocated to the stack is first loaded into 
13016          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13017          * the variable again.
13018          */
13019         orig_next_vreg = cfg->next_vreg;
13020         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13021         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13022         lvregs_len = 0;
13023
13024         /* 
13025          * These arrays contain the first and last instructions accessing a given
13026          * variable.
13027          * Since we emit bblocks in the same order we process them here, and we
13028          * don't split live ranges, these will precisely describe the live range of
13029          * the variable, i.e. the instruction range where a valid value can be found
13030          * in the variables location.
13031          * The live range is computed using the liveness info computed by the liveness pass.
13032          * We can't use vmv->range, since that is an abstract live range, and we need
13033          * one which is instruction precise.
13034          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13035          */
13036         /* FIXME: Only do this if debugging info is requested */
13037         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13038         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13039         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13040         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13041         
13042         /* Add spill loads/stores */
13043         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13044                 MonoInst *ins;
13045
13046                 if (cfg->verbose_level > 2)
13047                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13048
13049                 /* Clear vreg_to_lvreg array */
13050                 for (i = 0; i < lvregs_len; i++)
13051                         vreg_to_lvreg [lvregs [i]] = 0;
13052                 lvregs_len = 0;
13053
13054                 cfg->cbb = bb;
13055                 MONO_BB_FOR_EACH_INS (bb, ins) {
13056                         const char *spec = INS_INFO (ins->opcode);
13057                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13058                         gboolean store, no_lvreg;
13059                         int sregs [MONO_MAX_SRC_REGS];
13060
13061                         if (G_UNLIKELY (cfg->verbose_level > 2))
13062                                 mono_print_ins (ins);
13063
13064                         if (ins->opcode == OP_NOP)
13065                                 continue;
13066
13067                         /* 
13068                          * We handle LDADDR here as well, since it can only be decomposed
13069                          * when variable addresses are known.
13070                          */
13071                         if (ins->opcode == OP_LDADDR) {
13072                                 MonoInst *var = ins->inst_p0;
13073
13074                                 if (var->opcode == OP_VTARG_ADDR) {
13075                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13076                                         MonoInst *vtaddr = var->inst_left;
13077                                         if (vtaddr->opcode == OP_REGVAR) {
13078                                                 ins->opcode = OP_MOVE;
13079                                                 ins->sreg1 = vtaddr->dreg;
13080                                         }
13081                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13082                                                 ins->opcode = OP_LOAD_MEMBASE;
13083                                                 ins->inst_basereg = vtaddr->inst_basereg;
13084                                                 ins->inst_offset = vtaddr->inst_offset;
13085                                         } else
13086                                                 NOT_IMPLEMENTED;
13087                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13088                                         /* gsharedvt arg passed by ref */
13089                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13090
13091                                         ins->opcode = OP_LOAD_MEMBASE;
13092                                         ins->inst_basereg = var->inst_basereg;
13093                                         ins->inst_offset = var->inst_offset;
13094                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13095                                         MonoInst *load, *load2, *load3;
13096                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13097                                         int reg1, reg2, reg3;
13098                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13099                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13100
13101                                         /*
13102                                          * gsharedvt local.
13103                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13104                                          */
13105
13106                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13107
13108                                         g_assert (info_var);
13109                                         g_assert (locals_var);
13110
13111                                         /* Mark the instruction used to compute the locals var as used */
13112                                         cfg->gsharedvt_locals_var_ins = NULL;
13113
13114                                         /* Load the offset */
13115                                         if (info_var->opcode == OP_REGOFFSET) {
13116                                                 reg1 = alloc_ireg (cfg);
13117                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13118                                         } else if (info_var->opcode == OP_REGVAR) {
13119                                                 load = NULL;
13120                                                 reg1 = info_var->dreg;
13121                                         } else {
13122                                                 g_assert_not_reached ();
13123                                         }
13124                                         reg2 = alloc_ireg (cfg);
13125                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13126                                         /* Load the locals area address */
13127                                         reg3 = alloc_ireg (cfg);
13128                                         if (locals_var->opcode == OP_REGOFFSET) {
13129                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13130                                         } else if (locals_var->opcode == OP_REGVAR) {
13131                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13132                                         } else {
13133                                                 g_assert_not_reached ();
13134                                         }
13135                                         /* Compute the address */
13136                                         ins->opcode = OP_PADD;
13137                                         ins->sreg1 = reg3;
13138                                         ins->sreg2 = reg2;
13139
13140                                         mono_bblock_insert_before_ins (bb, ins, load3);
13141                                         mono_bblock_insert_before_ins (bb, load3, load2);
13142                                         if (load)
13143                                                 mono_bblock_insert_before_ins (bb, load2, load);
13144                                 } else {
13145                                         g_assert (var->opcode == OP_REGOFFSET);
13146
13147                                         ins->opcode = OP_ADD_IMM;
13148                                         ins->sreg1 = var->inst_basereg;
13149                                         ins->inst_imm = var->inst_offset;
13150                                 }
13151
13152                                 *need_local_opts = TRUE;
13153                                 spec = INS_INFO (ins->opcode);
13154                         }
13155
13156                         if (ins->opcode < MONO_CEE_LAST) {
13157                                 mono_print_ins (ins);
13158                                 g_assert_not_reached ();
13159                         }
13160
13161                         /*
13162                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13163                          * src register.
13164                          * FIXME:
13165                          */
13166                         if (MONO_IS_STORE_MEMBASE (ins)) {
13167                                 tmp_reg = ins->dreg;
13168                                 ins->dreg = ins->sreg2;
13169                                 ins->sreg2 = tmp_reg;
13170                                 store = TRUE;
13171
13172                                 spec2 [MONO_INST_DEST] = ' ';
13173                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13174                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13175                                 spec2 [MONO_INST_SRC3] = ' ';
13176                                 spec = spec2;
13177                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13178                                 g_assert_not_reached ();
13179                         else
13180                                 store = FALSE;
13181                         no_lvreg = FALSE;
13182
13183                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13184                                 printf ("\t %.3s %d", spec, ins->dreg);
13185                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13186                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13187                                         printf (" %d", sregs [srcindex]);
13188                                 printf ("\n");
13189                         }
13190
13191                         /***************/
13192                         /*    DREG     */
13193                         /***************/
13194                         regtype = spec [MONO_INST_DEST];
13195                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13196                         prev_dreg = -1;
13197
13198                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13199                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13200                                 MonoInst *store_ins;
13201                                 int store_opcode;
13202                                 MonoInst *def_ins = ins;
13203                                 int dreg = ins->dreg; /* The original vreg */
13204
13205                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13206
13207                                 if (var->opcode == OP_REGVAR) {
13208                                         ins->dreg = var->dreg;
13209                                 } 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)) {
13210                                         /* 
13211                                          * Instead of emitting a load+store, use a _membase opcode.
13212                                          */
13213                                         g_assert (var->opcode == OP_REGOFFSET);
13214                                         if (ins->opcode == OP_MOVE) {
13215                                                 NULLIFY_INS (ins);
13216                                                 def_ins = NULL;
13217                                         } else {
13218                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13219                                                 ins->inst_basereg = var->inst_basereg;
13220                                                 ins->inst_offset = var->inst_offset;
13221                                                 ins->dreg = -1;
13222                                         }
13223                                         spec = INS_INFO (ins->opcode);
13224                                 } else {
13225                                         guint32 lvreg;
13226
13227                                         g_assert (var->opcode == OP_REGOFFSET);
13228
13229                                         prev_dreg = ins->dreg;
13230
13231                                         /* Invalidate any previous lvreg for this vreg */
13232                                         vreg_to_lvreg [ins->dreg] = 0;
13233
13234                                         lvreg = 0;
13235
13236                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13237                                                 regtype = 'l';
13238                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13239                                         }
13240
13241                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13242
13243 #if SIZEOF_REGISTER != 8
13244                                         if (regtype == 'l') {
13245                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13246                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13247                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13248                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13249                                                 def_ins = store_ins;
13250                                         }
13251                                         else
13252 #endif
13253                                         {
13254                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13255
13256                                                 /* Try to fuse the store into the instruction itself */
13257                                                 /* FIXME: Add more instructions */
13258                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13259                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13260                                                         ins->inst_imm = ins->inst_c0;
13261                                                         ins->inst_destbasereg = var->inst_basereg;
13262                                                         ins->inst_offset = var->inst_offset;
13263                                                         spec = INS_INFO (ins->opcode);
13264                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13265                                                         ins->opcode = store_opcode;
13266                                                         ins->inst_destbasereg = var->inst_basereg;
13267                                                         ins->inst_offset = var->inst_offset;
13268
13269                                                         no_lvreg = TRUE;
13270
13271                                                         tmp_reg = ins->dreg;
13272                                                         ins->dreg = ins->sreg2;
13273                                                         ins->sreg2 = tmp_reg;
13274                                                         store = TRUE;
13275
13276                                                         spec2 [MONO_INST_DEST] = ' ';
13277                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13278                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13279                                                         spec2 [MONO_INST_SRC3] = ' ';
13280                                                         spec = spec2;
13281                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13282                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13283                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13284                                                         ins->dreg = -1;
13285                                                         ins->inst_basereg = var->inst_basereg;
13286                                                         ins->inst_offset = var->inst_offset;
13287                                                         spec = INS_INFO (ins->opcode);
13288                                                 } else {
13289                                                         /* printf ("INS: "); mono_print_ins (ins); */
13290                                                         /* Create a store instruction */
13291                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13292
13293                                                         /* Insert it after the instruction */
13294                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13295
13296                                                         def_ins = store_ins;
13297
13298                                                         /* 
13299                                                          * We can't assign ins->dreg to var->dreg here, since the
13300                                                          * sregs could use it. So set a flag, and do it after
13301                                                          * the sregs.
13302                                                          */
13303                                                         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)))
13304                                                                 dest_has_lvreg = TRUE;
13305                                                 }
13306                                         }
13307                                 }
13308
13309                                 if (def_ins && !live_range_start [dreg]) {
13310                                         live_range_start [dreg] = def_ins;
13311                                         live_range_start_bb [dreg] = bb;
13312                                 }
13313
13314                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13315                                         MonoInst *tmp;
13316
13317                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13318                                         tmp->inst_c1 = dreg;
13319                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13320                                 }
13321                         }
13322
13323                         /************/
13324                         /*  SREGS   */
13325                         /************/
13326                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13327                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13328                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13329                                 sreg = sregs [srcindex];
13330
13331                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13332                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13333                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13334                                         MonoInst *use_ins = ins;
13335                                         MonoInst *load_ins;
13336                                         guint32 load_opcode;
13337
13338                                         if (var->opcode == OP_REGVAR) {
13339                                                 sregs [srcindex] = var->dreg;
13340                                                 //mono_inst_set_src_registers (ins, sregs);
13341                                                 live_range_end [sreg] = use_ins;
13342                                                 live_range_end_bb [sreg] = bb;
13343
13344                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13345                                                         MonoInst *tmp;
13346
13347                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13348                                                         /* var->dreg is a hreg */
13349                                                         tmp->inst_c1 = sreg;
13350                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13351                                                 }
13352
13353                                                 continue;
13354                                         }
13355
13356                                         g_assert (var->opcode == OP_REGOFFSET);
13357                                                 
13358                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13359
13360                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13361
13362                                         if (vreg_to_lvreg [sreg]) {
13363                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13364
13365                                                 /* The variable is already loaded to an lvreg */
13366                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13367                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13368                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13369                                                 //mono_inst_set_src_registers (ins, sregs);
13370                                                 continue;
13371                                         }
13372
13373                                         /* Try to fuse the load into the instruction */
13374                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13375                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13376                                                 sregs [0] = var->inst_basereg;
13377                                                 //mono_inst_set_src_registers (ins, sregs);
13378                                                 ins->inst_offset = var->inst_offset;
13379                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13380                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13381                                                 sregs [1] = var->inst_basereg;
13382                                                 //mono_inst_set_src_registers (ins, sregs);
13383                                                 ins->inst_offset = var->inst_offset;
13384                                         } else {
13385                                                 if (MONO_IS_REAL_MOVE (ins)) {
13386                                                         ins->opcode = OP_NOP;
13387                                                         sreg = ins->dreg;
13388                                                 } else {
13389                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13390
13391                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13392
13393                                                         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) {
13394                                                                 if (var->dreg == prev_dreg) {
13395                                                                         /*
13396                                                                          * sreg refers to the value loaded by the load
13397                                                                          * emitted below, but we need to use ins->dreg
13398                                                                          * since it refers to the store emitted earlier.
13399                                                                          */
13400                                                                         sreg = ins->dreg;
13401                                                                 }
13402                                                                 g_assert (sreg != -1);
13403                                                                 vreg_to_lvreg [var->dreg] = sreg;
13404                                                                 g_assert (lvregs_len < 1024);
13405                                                                 lvregs [lvregs_len ++] = var->dreg;
13406                                                         }
13407                                                 }
13408
13409                                                 sregs [srcindex] = sreg;
13410                                                 //mono_inst_set_src_registers (ins, sregs);
13411
13412 #if SIZEOF_REGISTER != 8
13413                                                 if (regtype == 'l') {
13414                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13415                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13416                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13417                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13418                                                         use_ins = load_ins;
13419                                                 }
13420                                                 else
13421 #endif
13422                                                 {
13423 #if SIZEOF_REGISTER == 4
13424                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13425 #endif
13426                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13427                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13428                                                         use_ins = load_ins;
13429                                                 }
13430                                         }
13431
13432                                         if (var->dreg < orig_next_vreg) {
13433                                                 live_range_end [var->dreg] = use_ins;
13434                                                 live_range_end_bb [var->dreg] = bb;
13435                                         }
13436
13437                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13438                                                 MonoInst *tmp;
13439
13440                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13441                                                 tmp->inst_c1 = var->dreg;
13442                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13443                                         }
13444                                 }
13445                         }
13446                         mono_inst_set_src_registers (ins, sregs);
13447
13448                         if (dest_has_lvreg) {
13449                                 g_assert (ins->dreg != -1);
13450                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13451                                 g_assert (lvregs_len < 1024);
13452                                 lvregs [lvregs_len ++] = prev_dreg;
13453                                 dest_has_lvreg = FALSE;
13454                         }
13455
13456                         if (store) {
13457                                 tmp_reg = ins->dreg;
13458                                 ins->dreg = ins->sreg2;
13459                                 ins->sreg2 = tmp_reg;
13460                         }
13461
13462                         if (MONO_IS_CALL (ins)) {
13463                                 /* Clear vreg_to_lvreg array */
13464                                 for (i = 0; i < lvregs_len; i++)
13465                                         vreg_to_lvreg [lvregs [i]] = 0;
13466                                 lvregs_len = 0;
13467                         } else if (ins->opcode == OP_NOP) {
13468                                 ins->dreg = -1;
13469                                 MONO_INST_NULLIFY_SREGS (ins);
13470                         }
13471
13472                         if (cfg->verbose_level > 2)
13473                                 mono_print_ins_index (1, ins);
13474                 }
13475
13476                 /* Extend the live range based on the liveness info */
13477                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13478                         for (i = 0; i < cfg->num_varinfo; i ++) {
13479                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13480
13481                                 if (vreg_is_volatile (cfg, vi->vreg))
13482                                         /* The liveness info is incomplete */
13483                                         continue;
13484
13485                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13486                                         /* Live from at least the first ins of this bb */
13487                                         live_range_start [vi->vreg] = bb->code;
13488                                         live_range_start_bb [vi->vreg] = bb;
13489                                 }
13490
13491                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13492                                         /* Live at least until the last ins of this bb */
13493                                         live_range_end [vi->vreg] = bb->last_ins;
13494                                         live_range_end_bb [vi->vreg] = bb;
13495                                 }
13496                         }
13497                 }
13498         }
13499         
13500 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13501         /*
13502          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13503          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13504          */
13505         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13506                 for (i = 0; i < cfg->num_varinfo; ++i) {
13507                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13508                         MonoInst *ins;
13509
13510                         if (live_range_start [vreg]) {
13511                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13512                                 ins->inst_c0 = i;
13513                                 ins->inst_c1 = vreg;
13514                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13515                         }
13516                         if (live_range_end [vreg]) {
13517                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13518                                 ins->inst_c0 = i;
13519                                 ins->inst_c1 = vreg;
13520                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13521                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13522                                 else
13523                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13524                         }
13525                 }
13526         }
13527 #endif
13528
13529         if (cfg->gsharedvt_locals_var_ins) {
13530                 /* Nullify if unused */
13531                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13532                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13533         }
13534
13535         g_free (live_range_start);
13536         g_free (live_range_end);
13537         g_free (live_range_start_bb);
13538         g_free (live_range_end_bb);
13539 }
13540
13541 /**
13542  * FIXME:
13543  * - use 'iadd' instead of 'int_add'
13544  * - handling ovf opcodes: decompose in method_to_ir.
13545  * - unify iregs/fregs
13546  *   -> partly done, the missing parts are:
13547  *   - a more complete unification would involve unifying the hregs as well, so
13548  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13549  *     would no longer map to the machine hregs, so the code generators would need to
13550  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13551  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13552  *     fp/non-fp branches speeds it up by about 15%.
13553  * - use sext/zext opcodes instead of shifts
13554  * - add OP_ICALL
13555  * - get rid of TEMPLOADs if possible and use vregs instead
13556  * - clean up usage of OP_P/OP_ opcodes
13557  * - cleanup usage of DUMMY_USE
13558  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13559  *   stack
13560  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13561  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13562  * - make sure handle_stack_args () is called before the branch is emitted
13563  * - when the new IR is done, get rid of all unused stuff
13564  * - COMPARE/BEQ as separate instructions or unify them ?
13565  *   - keeping them separate allows specialized compare instructions like
13566  *     compare_imm, compare_membase
13567  *   - most back ends unify fp compare+branch, fp compare+ceq
13568  * - integrate mono_save_args into inline_method
13569  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13570  * - handle long shift opts on 32 bit platforms somehow: they require 
13571  *   3 sregs (2 for arg1 and 1 for arg2)
13572  * - make byref a 'normal' type.
13573  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13574  *   variable if needed.
13575  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13576  *   like inline_method.
13577  * - remove inlining restrictions
13578  * - fix LNEG and enable cfold of INEG
13579  * - generalize x86 optimizations like ldelema as a peephole optimization
13580  * - add store_mem_imm for amd64
13581  * - optimize the loading of the interruption flag in the managed->native wrappers
13582  * - avoid special handling of OP_NOP in passes
13583  * - move code inserting instructions into one function/macro.
13584  * - try a coalescing phase after liveness analysis
13585  * - add float -> vreg conversion + local optimizations on !x86
13586  * - figure out how to handle decomposed branches during optimizations, ie.
13587  *   compare+branch, op_jump_table+op_br etc.
13588  * - promote RuntimeXHandles to vregs
13589  * - vtype cleanups:
13590  *   - add a NEW_VARLOADA_VREG macro
13591  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13592  *   accessing vtype fields.
13593  * - get rid of I8CONST on 64 bit platforms
13594  * - dealing with the increase in code size due to branches created during opcode
13595  *   decomposition:
13596  *   - use extended basic blocks
13597  *     - all parts of the JIT
13598  *     - handle_global_vregs () && local regalloc
13599  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13600  * - sources of increase in code size:
13601  *   - vtypes
13602  *   - long compares
13603  *   - isinst and castclass
13604  *   - lvregs not allocated to global registers even if used multiple times
13605  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13606  *   meaningful.
13607  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13608  * - add all micro optimizations from the old JIT
13609  * - put tree optimizations into the deadce pass
13610  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13611  *   specific function.
13612  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13613  *   fcompare + branchCC.
13614  * - create a helper function for allocating a stack slot, taking into account 
13615  *   MONO_CFG_HAS_SPILLUP.
13616  * - merge r68207.
13617  * - merge the ia64 switch changes.
13618  * - optimize mono_regstate2_alloc_int/float.
13619  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13620  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13621  *   parts of the tree could be separated by other instructions, killing the tree
13622  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13623  *   instructions if the result of the load is used multiple times ?
13624  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13625  * - LAST MERGE: 108395.
13626  * - when returning vtypes in registers, generate IR and append it to the end of the
13627  *   last bb instead of doing it in the epilog.
13628  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13629  */
13630
13631 /*
13632
13633 NOTES
13634 -----
13635
13636 - When to decompose opcodes:
13637   - earlier: this makes some optimizations hard to implement, since the low level IR
13638   no longer contains the neccessary information. But it is easier to do.
13639   - later: harder to implement, enables more optimizations.
13640 - Branches inside bblocks:
13641   - created when decomposing complex opcodes. 
13642     - branches to another bblock: harmless, but not tracked by the branch 
13643       optimizations, so need to branch to a label at the start of the bblock.
13644     - branches to inside the same bblock: very problematic, trips up the local
13645       reg allocator. Can be fixed by spitting the current bblock, but that is a
13646       complex operation, since some local vregs can become global vregs etc.
13647 - Local/global vregs:
13648   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13649     local register allocator.
13650   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13651     structure, created by mono_create_var (). Assigned to hregs or the stack by
13652     the global register allocator.
13653 - When to do optimizations like alu->alu_imm:
13654   - earlier -> saves work later on since the IR will be smaller/simpler
13655   - later -> can work on more instructions
13656 - Handling of valuetypes:
13657   - When a vtype is pushed on the stack, a new temporary is created, an 
13658     instruction computing its address (LDADDR) is emitted and pushed on
13659     the stack. Need to optimize cases when the vtype is used immediately as in
13660     argument passing, stloc etc.
13661 - Instead of the to_end stuff in the old JIT, simply call the function handling
13662   the values on the stack before emitting the last instruction of the bb.
13663 */
13664
13665 #endif /* DISABLE_JIT */