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