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