2e35b7ab17f8ef7677be8b3e9db35455f0670e71
[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_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_replace_type (type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return OP_MOVE;
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368 }
369
370 /*
371  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
372  * foo<T> (int i) { ldarg.0; box T; }
373  */
374 #define UNVERIFIED do { \
375         if (cfg->gsharedvt) { \
376                 if (cfg->verbose_level > 2)                                                                     \
377                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
378                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
379                 goto exception_exit;                                                                                    \
380         }                                                                                                                                       \
381         if (mini_get_debug_options ()->break_on_unverified) \
382                 G_BREAKPOINT (); \
383         else \
384                 goto unverified; \
385 } while (0)
386
387 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
388
389 #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)
390
391 #define GET_BBLOCK(cfg,tblock,ip) do {  \
392                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
393                 if (!(tblock)) {        \
394                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
395             NEW_BBLOCK (cfg, (tblock)); \
396                         (tblock)->cil_code = (ip);      \
397                         ADD_BBLOCK (cfg, (tblock));     \
398                 } \
399         } while (0)
400
401 #if defined(TARGET_X86) || defined(TARGET_AMD64)
402 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
403                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
404                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
405                 (dest)->sreg1 = (sr1); \
406                 (dest)->sreg2 = (sr2); \
407                 (dest)->inst_imm = (imm); \
408                 (dest)->backend.shift_amount = (shift); \
409                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
410         } while (0)
411 #endif
412
413 #if SIZEOF_REGISTER == 8
414 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
415                 /* FIXME: Need to add many more cases */ \
416                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
417                         MonoInst *widen; \
418                         int dr = alloc_preg (cfg); \
419                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
420                         (ins)->sreg2 = widen->dreg; \
421                 } \
422         } while (0)
423 #else
424 #define ADD_WIDEN_OP(ins, arg1, arg2)
425 #endif
426
427 #define ADD_BINOP(op) do {      \
428                 MONO_INST_NEW (cfg, ins, (op)); \
429                 sp -= 2;        \
430                 ins->sreg1 = sp [0]->dreg;      \
431                 ins->sreg2 = sp [1]->dreg;      \
432                 type_from_op (ins, sp [0], sp [1]);     \
433                 CHECK_TYPE (ins);       \
434                 /* Have to insert a widening op */               \
435         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
436         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
437         MONO_ADD_INS ((cfg)->cbb, (ins)); \
438         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
439         } while (0)
440
441 #define ADD_UNOP(op) do {       \
442                 MONO_INST_NEW (cfg, ins, (op)); \
443                 sp--;   \
444                 ins->sreg1 = sp [0]->dreg;      \
445                 type_from_op (ins, sp [0], NULL);       \
446                 CHECK_TYPE (ins);       \
447         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
448         MONO_ADD_INS ((cfg)->cbb, (ins)); \
449                 *sp++ = mono_decompose_opcode (cfg, ins); \
450         } while (0)
451
452 #define ADD_BINCOND(next_block) do {    \
453                 MonoInst *cmp;  \
454                 sp -= 2; \
455                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
456                 cmp->sreg1 = sp [0]->dreg;      \
457                 cmp->sreg2 = sp [1]->dreg;      \
458                 type_from_op (cmp, sp [0], sp [1]);     \
459                 CHECK_TYPE (cmp);       \
460                 type_from_op (ins, sp [0], sp [1]);     \
461                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
462                 GET_BBLOCK (cfg, tblock, target);               \
463                 link_bblock (cfg, bblock, tblock);      \
464                 ins->inst_true_bb = tblock;     \
465                 if ((next_block)) {     \
466                         link_bblock (cfg, bblock, (next_block));        \
467                         ins->inst_false_bb = (next_block);      \
468                         start_new_bblock = 1;   \
469                 } else {        \
470                         GET_BBLOCK (cfg, tblock, ip);           \
471                         link_bblock (cfg, bblock, tblock);      \
472                         ins->inst_false_bb = tblock;    \
473                         start_new_bblock = 2;   \
474                 }       \
475                 if (sp != stack_start) {                                                                        \
476                     handle_stack_args (cfg, stack_start, sp - stack_start); \
477                         CHECK_UNVERIFIABLE (cfg); \
478                 } \
479         MONO_ADD_INS (bblock, cmp); \
480                 MONO_ADD_INS (bblock, ins);     \
481         } while (0)
482
483 /* *
484  * link_bblock: Links two basic blocks
485  *
486  * links two basic blocks in the control flow graph, the 'from'
487  * argument is the starting block and the 'to' argument is the block
488  * the control flow ends to after 'from'.
489  */
490 static void
491 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
492 {
493         MonoBasicBlock **newa;
494         int i, found;
495
496 #if 0
497         if (from->cil_code) {
498                 if (to->cil_code)
499                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
500                 else
501                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
502         } else {
503                 if (to->cil_code)
504                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
505                 else
506                         printf ("edge from entry to exit\n");
507         }
508 #endif
509
510         found = FALSE;
511         for (i = 0; i < from->out_count; ++i) {
512                 if (to == from->out_bb [i]) {
513                         found = TRUE;
514                         break;
515                 }
516         }
517         if (!found) {
518                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
519                 for (i = 0; i < from->out_count; ++i) {
520                         newa [i] = from->out_bb [i];
521                 }
522                 newa [i] = to;
523                 from->out_count++;
524                 from->out_bb = newa;
525         }
526
527         found = FALSE;
528         for (i = 0; i < to->in_count; ++i) {
529                 if (from == to->in_bb [i]) {
530                         found = TRUE;
531                         break;
532                 }
533         }
534         if (!found) {
535                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
536                 for (i = 0; i < to->in_count; ++i) {
537                         newa [i] = to->in_bb [i];
538                 }
539                 newa [i] = from;
540                 to->in_count++;
541                 to->in_bb = newa;
542         }
543 }
544
545 void
546 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
547 {
548         link_bblock (cfg, from, to);
549 }
550
551 /**
552  * mono_find_block_region:
553  *
554  *   We mark each basic block with a region ID. We use that to avoid BB
555  *   optimizations when blocks are in different regions.
556  *
557  * Returns:
558  *   A region token that encodes where this region is, and information
559  *   about the clause owner for this block.
560  *
561  *   The region encodes the try/catch/filter clause that owns this block
562  *   as well as the type.  -1 is a special value that represents a block
563  *   that is in none of try/catch/filter.
564  */
565 static int
566 mono_find_block_region (MonoCompile *cfg, int offset)
567 {
568         MonoMethodHeader *header = cfg->header;
569         MonoExceptionClause *clause;
570         int i;
571
572         for (i = 0; i < header->num_clauses; ++i) {
573                 clause = &header->clauses [i];
574                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
575                     (offset < (clause->handler_offset)))
576                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
577                            
578                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
579                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
580                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
581                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
582                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
583                         else
584                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
585                 }
586
587                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
588                         return ((i + 1) << 8) | clause->flags;
589         }
590
591         return -1;
592 }
593
594 static GList*
595 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
596 {
597         MonoMethodHeader *header = cfg->header;
598         MonoExceptionClause *clause;
599         int i;
600         GList *res = NULL;
601
602         for (i = 0; i < header->num_clauses; ++i) {
603                 clause = &header->clauses [i];
604                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
605                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
606                         if (clause->flags == type)
607                                 res = g_list_append (res, clause);
608                 }
609         }
610         return res;
611 }
612
613 static void
614 mono_create_spvar_for_region (MonoCompile *cfg, int region)
615 {
616         MonoInst *var;
617
618         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
619         if (var)
620                 return;
621
622         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
623         /* prevent it from being register allocated */
624         var->flags |= MONO_INST_VOLATILE;
625
626         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
627 }
628
629 MonoInst *
630 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
631 {
632         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
633 }
634
635 static MonoInst*
636 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
637 {
638         MonoInst *var;
639
640         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
641         if (var)
642                 return var;
643
644         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
645         /* prevent it from being register allocated */
646         var->flags |= MONO_INST_VOLATILE;
647
648         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
649
650         return var;
651 }
652
653 /*
654  * Returns the type used in the eval stack when @type is loaded.
655  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
656  */
657 void
658 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
659 {
660         MonoClass *klass;
661
662         type = mini_replace_type (type);
663         inst->klass = klass = mono_class_from_mono_type (type);
664         if (type->byref) {
665                 inst->type = STACK_MP;
666                 return;
667         }
668
669 handle_enum:
670         switch (type->type) {
671         case MONO_TYPE_VOID:
672                 inst->type = STACK_INV;
673                 return;
674         case MONO_TYPE_I1:
675         case MONO_TYPE_U1:
676         case MONO_TYPE_BOOLEAN:
677         case MONO_TYPE_I2:
678         case MONO_TYPE_U2:
679         case MONO_TYPE_CHAR:
680         case MONO_TYPE_I4:
681         case MONO_TYPE_U4:
682                 inst->type = STACK_I4;
683                 return;
684         case MONO_TYPE_I:
685         case MONO_TYPE_U:
686         case MONO_TYPE_PTR:
687         case MONO_TYPE_FNPTR:
688                 inst->type = STACK_PTR;
689                 return;
690         case MONO_TYPE_CLASS:
691         case MONO_TYPE_STRING:
692         case MONO_TYPE_OBJECT:
693         case MONO_TYPE_SZARRAY:
694         case MONO_TYPE_ARRAY:    
695                 inst->type = STACK_OBJ;
696                 return;
697         case MONO_TYPE_I8:
698         case MONO_TYPE_U8:
699                 inst->type = STACK_I8;
700                 return;
701         case MONO_TYPE_R4:
702         case MONO_TYPE_R8:
703                 inst->type = STACK_R8;
704                 return;
705         case MONO_TYPE_VALUETYPE:
706                 if (type->data.klass->enumtype) {
707                         type = mono_class_enum_basetype (type->data.klass);
708                         goto handle_enum;
709                 } else {
710                         inst->klass = klass;
711                         inst->type = STACK_VTYPE;
712                         return;
713                 }
714         case MONO_TYPE_TYPEDBYREF:
715                 inst->klass = mono_defaults.typed_reference_class;
716                 inst->type = STACK_VTYPE;
717                 return;
718         case MONO_TYPE_GENERICINST:
719                 type = &type->data.generic_class->container_class->byval_arg;
720                 goto handle_enum;
721         case MONO_TYPE_VAR:
722         case MONO_TYPE_MVAR:
723                 g_assert (cfg->generic_sharing_context);
724                 if (mini_is_gsharedvt_type (cfg, type)) {
725                         g_assert (cfg->gsharedvt);
726                         inst->type = STACK_VTYPE;
727                 } else {
728                         inst->type = STACK_OBJ;
729                 }
730                 return;
731         default:
732                 g_error ("unknown type 0x%02x in eval stack type", type->type);
733         }
734 }
735
736 /*
737  * The following tables are used to quickly validate the IL code in type_from_op ().
738  */
739 static const char
740 bin_num_table [STACK_MAX] [STACK_MAX] = {
741         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
742         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
743         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
744         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
745         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
746         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
747         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
748         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
749 };
750
751 static const char 
752 neg_table [] = {
753         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
754 };
755
756 /* reduce the size of this table */
757 static const char
758 bin_int_table [STACK_MAX] [STACK_MAX] = {
759         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
760         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
761         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
762         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
763         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
764         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
765         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
766         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
767 };
768
769 static const char
770 bin_comp_table [STACK_MAX] [STACK_MAX] = {
771 /*      Inv i  L  p  F  &  O  vt */
772         {0},
773         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
774         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
775         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
776         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
777         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
778         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
779         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
780 };
781
782 /* reduce the size of this table */
783 static const char
784 shift_table [STACK_MAX] [STACK_MAX] = {
785         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
786         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
787         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
788         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
789         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
790         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
791         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
792         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
793 };
794
795 /*
796  * Tables to map from the non-specific opcode to the matching
797  * type-specific opcode.
798  */
799 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
800 static const guint16
801 binops_op_map [STACK_MAX] = {
802         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
803 };
804
805 /* handles from CEE_NEG to CEE_CONV_U8 */
806 static const guint16
807 unops_op_map [STACK_MAX] = {
808         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
809 };
810
811 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
812 static const guint16
813 ovfops_op_map [STACK_MAX] = {
814         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
815 };
816
817 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
818 static const guint16
819 ovf2ops_op_map [STACK_MAX] = {
820         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
821 };
822
823 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
824 static const guint16
825 ovf3ops_op_map [STACK_MAX] = {
826         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
827 };
828
829 /* handles from CEE_BEQ to CEE_BLT_UN */
830 static const guint16
831 beqops_op_map [STACK_MAX] = {
832         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
833 };
834
835 /* handles from CEE_CEQ to CEE_CLT_UN */
836 static const guint16
837 ceqops_op_map [STACK_MAX] = {
838         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
839 };
840
841 /*
842  * Sets ins->type (the type on the eval stack) according to the
843  * type of the opcode and the arguments to it.
844  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
845  *
846  * FIXME: this function sets ins->type unconditionally in some cases, but
847  * it should set it to invalid for some types (a conv.x on an object)
848  */
849 static void
850 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
851
852         switch (ins->opcode) {
853         /* binops */
854         case CEE_ADD:
855         case CEE_SUB:
856         case CEE_MUL:
857         case CEE_DIV:
858         case CEE_REM:
859                 /* FIXME: check unverifiable args for STACK_MP */
860                 ins->type = bin_num_table [src1->type] [src2->type];
861                 ins->opcode += binops_op_map [ins->type];
862                 break;
863         case CEE_DIV_UN:
864         case CEE_REM_UN:
865         case CEE_AND:
866         case CEE_OR:
867         case CEE_XOR:
868                 ins->type = bin_int_table [src1->type] [src2->type];
869                 ins->opcode += binops_op_map [ins->type];
870                 break;
871         case CEE_SHL:
872         case CEE_SHR:
873         case CEE_SHR_UN:
874                 ins->type = shift_table [src1->type] [src2->type];
875                 ins->opcode += binops_op_map [ins->type];
876                 break;
877         case OP_COMPARE:
878         case OP_LCOMPARE:
879         case OP_ICOMPARE:
880                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
881                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
882                         ins->opcode = OP_LCOMPARE;
883                 else if (src1->type == STACK_R8)
884                         ins->opcode = OP_FCOMPARE;
885                 else
886                         ins->opcode = OP_ICOMPARE;
887                 break;
888         case OP_ICOMPARE_IMM:
889                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
890                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
891                         ins->opcode = OP_LCOMPARE_IMM;          
892                 break;
893         case CEE_BEQ:
894         case CEE_BGE:
895         case CEE_BGT:
896         case CEE_BLE:
897         case CEE_BLT:
898         case CEE_BNE_UN:
899         case CEE_BGE_UN:
900         case CEE_BGT_UN:
901         case CEE_BLE_UN:
902         case CEE_BLT_UN:
903                 ins->opcode += beqops_op_map [src1->type];
904                 break;
905         case OP_CEQ:
906                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
907                 ins->opcode += ceqops_op_map [src1->type];
908                 break;
909         case OP_CGT:
910         case OP_CGT_UN:
911         case OP_CLT:
912         case OP_CLT_UN:
913                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
914                 ins->opcode += ceqops_op_map [src1->type];
915                 break;
916         /* unops */
917         case CEE_NEG:
918                 ins->type = neg_table [src1->type];
919                 ins->opcode += unops_op_map [ins->type];
920                 break;
921         case CEE_NOT:
922                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
923                         ins->type = src1->type;
924                 else
925                         ins->type = STACK_INV;
926                 ins->opcode += unops_op_map [ins->type];
927                 break;
928         case CEE_CONV_I1:
929         case CEE_CONV_I2:
930         case CEE_CONV_I4:
931         case CEE_CONV_U4:
932                 ins->type = STACK_I4;
933                 ins->opcode += unops_op_map [src1->type];
934                 break;
935         case CEE_CONV_R_UN:
936                 ins->type = STACK_R8;
937                 switch (src1->type) {
938                 case STACK_I4:
939                 case STACK_PTR:
940                         ins->opcode = OP_ICONV_TO_R_UN;
941                         break;
942                 case STACK_I8:
943                         ins->opcode = OP_LCONV_TO_R_UN; 
944                         break;
945                 }
946                 break;
947         case CEE_CONV_OVF_I1:
948         case CEE_CONV_OVF_U1:
949         case CEE_CONV_OVF_I2:
950         case CEE_CONV_OVF_U2:
951         case CEE_CONV_OVF_I4:
952         case CEE_CONV_OVF_U4:
953                 ins->type = STACK_I4;
954                 ins->opcode += ovf3ops_op_map [src1->type];
955                 break;
956         case CEE_CONV_OVF_I_UN:
957         case CEE_CONV_OVF_U_UN:
958                 ins->type = STACK_PTR;
959                 ins->opcode += ovf2ops_op_map [src1->type];
960                 break;
961         case CEE_CONV_OVF_I1_UN:
962         case CEE_CONV_OVF_I2_UN:
963         case CEE_CONV_OVF_I4_UN:
964         case CEE_CONV_OVF_U1_UN:
965         case CEE_CONV_OVF_U2_UN:
966         case CEE_CONV_OVF_U4_UN:
967                 ins->type = STACK_I4;
968                 ins->opcode += ovf2ops_op_map [src1->type];
969                 break;
970         case CEE_CONV_U:
971                 ins->type = STACK_PTR;
972                 switch (src1->type) {
973                 case STACK_I4:
974                         ins->opcode = OP_ICONV_TO_U;
975                         break;
976                 case STACK_PTR:
977                 case STACK_MP:
978 #if SIZEOF_VOID_P == 8
979                         ins->opcode = OP_LCONV_TO_U;
980 #else
981                         ins->opcode = OP_MOVE;
982 #endif
983                         break;
984                 case STACK_I8:
985                         ins->opcode = OP_LCONV_TO_U;
986                         break;
987                 case STACK_R8:
988                         ins->opcode = OP_FCONV_TO_U;
989                         break;
990                 }
991                 break;
992         case CEE_CONV_I8:
993         case CEE_CONV_U8:
994                 ins->type = STACK_I8;
995                 ins->opcode += unops_op_map [src1->type];
996                 break;
997         case CEE_CONV_OVF_I8:
998         case CEE_CONV_OVF_U8:
999                 ins->type = STACK_I8;
1000                 ins->opcode += ovf3ops_op_map [src1->type];
1001                 break;
1002         case CEE_CONV_OVF_U8_UN:
1003         case CEE_CONV_OVF_I8_UN:
1004                 ins->type = STACK_I8;
1005                 ins->opcode += ovf2ops_op_map [src1->type];
1006                 break;
1007         case CEE_CONV_R4:
1008         case CEE_CONV_R8:
1009                 ins->type = STACK_R8;
1010                 ins->opcode += unops_op_map [src1->type];
1011                 break;
1012         case OP_CKFINITE:
1013                 ins->type = STACK_R8;           
1014                 break;
1015         case CEE_CONV_U2:
1016         case CEE_CONV_U1:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += ovfops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_I:
1021         case CEE_CONV_OVF_I:
1022         case CEE_CONV_OVF_U:
1023                 ins->type = STACK_PTR;
1024                 ins->opcode += ovfops_op_map [src1->type];
1025                 break;
1026         case CEE_ADD_OVF:
1027         case CEE_ADD_OVF_UN:
1028         case CEE_MUL_OVF:
1029         case CEE_MUL_OVF_UN:
1030         case CEE_SUB_OVF:
1031         case CEE_SUB_OVF_UN:
1032                 ins->type = bin_num_table [src1->type] [src2->type];
1033                 ins->opcode += ovfops_op_map [src1->type];
1034                 if (ins->type == STACK_R8)
1035                         ins->type = STACK_INV;
1036                 break;
1037         case OP_LOAD_MEMBASE:
1038                 ins->type = STACK_PTR;
1039                 break;
1040         case OP_LOADI1_MEMBASE:
1041         case OP_LOADU1_MEMBASE:
1042         case OP_LOADI2_MEMBASE:
1043         case OP_LOADU2_MEMBASE:
1044         case OP_LOADI4_MEMBASE:
1045         case OP_LOADU4_MEMBASE:
1046                 ins->type = STACK_PTR;
1047                 break;
1048         case OP_LOADI8_MEMBASE:
1049                 ins->type = STACK_I8;
1050                 break;
1051         case OP_LOADR4_MEMBASE:
1052         case OP_LOADR8_MEMBASE:
1053                 ins->type = STACK_R8;
1054                 break;
1055         default:
1056                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1057                 break;
1058         }
1059
1060         if (ins->type == STACK_MP)
1061                 ins->klass = mono_defaults.object_class;
1062 }
1063
1064 static const char 
1065 ldind_type [] = {
1066         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1067 };
1068
1069 #if 0
1070
1071 static const char
1072 param_table [STACK_MAX] [STACK_MAX] = {
1073         {0},
1074 };
1075
1076 static int
1077 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1078         int i;
1079
1080         if (sig->hasthis) {
1081                 switch (args->type) {
1082                 case STACK_I4:
1083                 case STACK_I8:
1084                 case STACK_R8:
1085                 case STACK_VTYPE:
1086                 case STACK_INV:
1087                         return 0;
1088                 }
1089                 args++;
1090         }
1091         for (i = 0; i < sig->param_count; ++i) {
1092                 switch (args [i].type) {
1093                 case STACK_INV:
1094                         return 0;
1095                 case STACK_MP:
1096                         if (!sig->params [i]->byref)
1097                                 return 0;
1098                         continue;
1099                 case STACK_OBJ:
1100                         if (sig->params [i]->byref)
1101                                 return 0;
1102                         switch (sig->params [i]->type) {
1103                         case MONO_TYPE_CLASS:
1104                         case MONO_TYPE_STRING:
1105                         case MONO_TYPE_OBJECT:
1106                         case MONO_TYPE_SZARRAY:
1107                         case MONO_TYPE_ARRAY:
1108                                 break;
1109                         default:
1110                                 return 0;
1111                         }
1112                         continue;
1113                 case STACK_R8:
1114                         if (sig->params [i]->byref)
1115                                 return 0;
1116                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1117                                 return 0;
1118                         continue;
1119                 case STACK_PTR:
1120                 case STACK_I4:
1121                 case STACK_I8:
1122                 case STACK_VTYPE:
1123                         break;
1124                 }
1125                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1126                         return 0;*/
1127         }
1128         return 1;
1129 }
1130 #endif
1131
1132 /*
1133  * When we need a pointer to the current domain many times in a method, we
1134  * call mono_domain_get() once and we store the result in a local variable.
1135  * This function returns the variable that represents the MonoDomain*.
1136  */
1137 inline static MonoInst *
1138 mono_get_domainvar (MonoCompile *cfg)
1139 {
1140         if (!cfg->domainvar)
1141                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1142         return cfg->domainvar;
1143 }
1144
1145 /*
1146  * The got_var contains the address of the Global Offset Table when AOT 
1147  * compiling.
1148  */
1149 MonoInst *
1150 mono_get_got_var (MonoCompile *cfg)
1151 {
1152 #ifdef MONO_ARCH_NEED_GOT_VAR
1153         if (!cfg->compile_aot)
1154                 return NULL;
1155         if (!cfg->got_var) {
1156                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1157         }
1158         return cfg->got_var;
1159 #else
1160         return NULL;
1161 #endif
1162 }
1163
1164 static MonoInst *
1165 mono_get_vtable_var (MonoCompile *cfg)
1166 {
1167         g_assert (cfg->generic_sharing_context);
1168
1169         if (!cfg->rgctx_var) {
1170                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1171                 /* force the var to be stack allocated */
1172                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1173         }
1174
1175         return cfg->rgctx_var;
1176 }
1177
1178 static MonoType*
1179 type_from_stack_type (MonoInst *ins) {
1180         switch (ins->type) {
1181         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1182         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1183         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1184         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1185         case STACK_MP:
1186                 return &ins->klass->this_arg;
1187         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1188         case STACK_VTYPE: return &ins->klass->byval_arg;
1189         default:
1190                 g_error ("stack type %d to monotype not handled\n", ins->type);
1191         }
1192         return NULL;
1193 }
1194
1195 static G_GNUC_UNUSED int
1196 type_to_stack_type (MonoType *t)
1197 {
1198         t = mono_type_get_underlying_type (t);
1199         switch (t->type) {
1200         case MONO_TYPE_I1:
1201         case MONO_TYPE_U1:
1202         case MONO_TYPE_BOOLEAN:
1203         case MONO_TYPE_I2:
1204         case MONO_TYPE_U2:
1205         case MONO_TYPE_CHAR:
1206         case MONO_TYPE_I4:
1207         case MONO_TYPE_U4:
1208                 return STACK_I4;
1209         case MONO_TYPE_I:
1210         case MONO_TYPE_U:
1211         case MONO_TYPE_PTR:
1212         case MONO_TYPE_FNPTR:
1213                 return STACK_PTR;
1214         case MONO_TYPE_CLASS:
1215         case MONO_TYPE_STRING:
1216         case MONO_TYPE_OBJECT:
1217         case MONO_TYPE_SZARRAY:
1218         case MONO_TYPE_ARRAY:    
1219                 return STACK_OBJ;
1220         case MONO_TYPE_I8:
1221         case MONO_TYPE_U8:
1222                 return STACK_I8;
1223         case MONO_TYPE_R4:
1224         case MONO_TYPE_R8:
1225                 return STACK_R8;
1226         case MONO_TYPE_VALUETYPE:
1227         case MONO_TYPE_TYPEDBYREF:
1228                 return STACK_VTYPE;
1229         case MONO_TYPE_GENERICINST:
1230                 if (mono_type_generic_inst_is_valuetype (t))
1231                         return STACK_VTYPE;
1232                 else
1233                         return STACK_OBJ;
1234                 break;
1235         default:
1236                 g_assert_not_reached ();
1237         }
1238
1239         return -1;
1240 }
1241
1242 static MonoClass*
1243 array_access_to_klass (int opcode)
1244 {
1245         switch (opcode) {
1246         case CEE_LDELEM_U1:
1247                 return mono_defaults.byte_class;
1248         case CEE_LDELEM_U2:
1249                 return mono_defaults.uint16_class;
1250         case CEE_LDELEM_I:
1251         case CEE_STELEM_I:
1252                 return mono_defaults.int_class;
1253         case CEE_LDELEM_I1:
1254         case CEE_STELEM_I1:
1255                 return mono_defaults.sbyte_class;
1256         case CEE_LDELEM_I2:
1257         case CEE_STELEM_I2:
1258                 return mono_defaults.int16_class;
1259         case CEE_LDELEM_I4:
1260         case CEE_STELEM_I4:
1261                 return mono_defaults.int32_class;
1262         case CEE_LDELEM_U4:
1263                 return mono_defaults.uint32_class;
1264         case CEE_LDELEM_I8:
1265         case CEE_STELEM_I8:
1266                 return mono_defaults.int64_class;
1267         case CEE_LDELEM_R4:
1268         case CEE_STELEM_R4:
1269                 return mono_defaults.single_class;
1270         case CEE_LDELEM_R8:
1271         case CEE_STELEM_R8:
1272                 return mono_defaults.double_class;
1273         case CEE_LDELEM_REF:
1274         case CEE_STELEM_REF:
1275                 return mono_defaults.object_class;
1276         default:
1277                 g_assert_not_reached ();
1278         }
1279         return NULL;
1280 }
1281
1282 /*
1283  * We try to share variables when possible
1284  */
1285 static MonoInst *
1286 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1287 {
1288         MonoInst *res;
1289         int pos, vnum;
1290
1291         /* inlining can result in deeper stacks */ 
1292         if (slot >= cfg->header->max_stack)
1293                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1294
1295         pos = ins->type - 1 + slot * STACK_MAX;
1296
1297         switch (ins->type) {
1298         case STACK_I4:
1299         case STACK_I8:
1300         case STACK_R8:
1301         case STACK_PTR:
1302         case STACK_MP:
1303         case STACK_OBJ:
1304                 if ((vnum = cfg->intvars [pos]))
1305                         return cfg->varinfo [vnum];
1306                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1307                 cfg->intvars [pos] = res->inst_c0;
1308                 break;
1309         default:
1310                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1311         }
1312         return res;
1313 }
1314
1315 static void
1316 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1317 {
1318         /* 
1319          * Don't use this if a generic_context is set, since that means AOT can't
1320          * look up the method using just the image+token.
1321          * table == 0 means this is a reference made from a wrapper.
1322          */
1323         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1324                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1325                 jump_info_token->image = image;
1326                 jump_info_token->token = token;
1327                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1328         }
1329 }
1330
1331 /*
1332  * This function is called to handle items that are left on the evaluation stack
1333  * at basic block boundaries. What happens is that we save the values to local variables
1334  * and we reload them later when first entering the target basic block (with the
1335  * handle_loaded_temps () function).
1336  * A single joint point will use the same variables (stored in the array bb->out_stack or
1337  * bb->in_stack, if the basic block is before or after the joint point).
1338  *
1339  * This function needs to be called _before_ emitting the last instruction of
1340  * the bb (i.e. before emitting a branch).
1341  * If the stack merge fails at a join point, cfg->unverifiable is set.
1342  */
1343 static void
1344 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1345 {
1346         int i, bindex;
1347         MonoBasicBlock *bb = cfg->cbb;
1348         MonoBasicBlock *outb;
1349         MonoInst *inst, **locals;
1350         gboolean found;
1351
1352         if (!count)
1353                 return;
1354         if (cfg->verbose_level > 3)
1355                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1356         if (!bb->out_scount) {
1357                 bb->out_scount = count;
1358                 //printf ("bblock %d has out:", bb->block_num);
1359                 found = FALSE;
1360                 for (i = 0; i < bb->out_count; ++i) {
1361                         outb = bb->out_bb [i];
1362                         /* exception handlers are linked, but they should not be considered for stack args */
1363                         if (outb->flags & BB_EXCEPTION_HANDLER)
1364                                 continue;
1365                         //printf (" %d", outb->block_num);
1366                         if (outb->in_stack) {
1367                                 found = TRUE;
1368                                 bb->out_stack = outb->in_stack;
1369                                 break;
1370                         }
1371                 }
1372                 //printf ("\n");
1373                 if (!found) {
1374                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1375                         for (i = 0; i < count; ++i) {
1376                                 /* 
1377                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1378                                  * stack slot and if they are of the same type.
1379                                  * This won't cause conflicts since if 'local' is used to 
1380                                  * store one of the values in the in_stack of a bblock, then
1381                                  * the same variable will be used for the same outgoing stack 
1382                                  * slot as well. 
1383                                  * This doesn't work when inlining methods, since the bblocks
1384                                  * in the inlined methods do not inherit their in_stack from
1385                                  * the bblock they are inlined to. See bug #58863 for an
1386                                  * example.
1387                                  */
1388                                 if (cfg->inlined_method)
1389                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1390                                 else
1391                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1392                         }
1393                 }
1394         }
1395
1396         for (i = 0; i < bb->out_count; ++i) {
1397                 outb = bb->out_bb [i];
1398                 /* exception handlers are linked, but they should not be considered for stack args */
1399                 if (outb->flags & BB_EXCEPTION_HANDLER)
1400                         continue;
1401                 if (outb->in_scount) {
1402                         if (outb->in_scount != bb->out_scount) {
1403                                 cfg->unverifiable = TRUE;
1404                                 return;
1405                         }
1406                         continue; /* check they are the same locals */
1407                 }
1408                 outb->in_scount = count;
1409                 outb->in_stack = bb->out_stack;
1410         }
1411
1412         locals = bb->out_stack;
1413         cfg->cbb = bb;
1414         for (i = 0; i < count; ++i) {
1415                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1416                 inst->cil_code = sp [i]->cil_code;
1417                 sp [i] = locals [i];
1418                 if (cfg->verbose_level > 3)
1419                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1420         }
1421
1422         /*
1423          * It is possible that the out bblocks already have in_stack assigned, and
1424          * the in_stacks differ. In this case, we will store to all the different 
1425          * in_stacks.
1426          */
1427
1428         found = TRUE;
1429         bindex = 0;
1430         while (found) {
1431                 /* Find a bblock which has a different in_stack */
1432                 found = FALSE;
1433                 while (bindex < bb->out_count) {
1434                         outb = bb->out_bb [bindex];
1435                         /* exception handlers are linked, but they should not be considered for stack args */
1436                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1437                                 bindex++;
1438                                 continue;
1439                         }
1440                         if (outb->in_stack != locals) {
1441                                 for (i = 0; i < count; ++i) {
1442                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1443                                         inst->cil_code = sp [i]->cil_code;
1444                                         sp [i] = locals [i];
1445                                         if (cfg->verbose_level > 3)
1446                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1447                                 }
1448                                 locals = outb->in_stack;
1449                                 found = TRUE;
1450                                 break;
1451                         }
1452                         bindex ++;
1453                 }
1454         }
1455 }
1456
1457 /* Emit code which loads interface_offsets [klass->interface_id]
1458  * The array is stored in memory before vtable.
1459 */
1460 static void
1461 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1462 {
1463         if (cfg->compile_aot) {
1464                 int ioffset_reg = alloc_preg (cfg);
1465                 int iid_reg = alloc_preg (cfg);
1466
1467                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1468                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1469                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1470         }
1471         else {
1472                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1473         }
1474 }
1475
1476 static void
1477 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1478 {
1479         int ibitmap_reg = alloc_preg (cfg);
1480 #ifdef COMPRESSED_INTERFACE_BITMAP
1481         MonoInst *args [2];
1482         MonoInst *res, *ins;
1483         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1484         MONO_ADD_INS (cfg->cbb, ins);
1485         args [0] = ins;
1486         if (cfg->compile_aot)
1487                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1488         else
1489                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1490         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1491         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1492 #else
1493         int ibitmap_byte_reg = alloc_preg (cfg);
1494
1495         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1496
1497         if (cfg->compile_aot) {
1498                 int iid_reg = alloc_preg (cfg);
1499                 int shifted_iid_reg = alloc_preg (cfg);
1500                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1501                 int masked_iid_reg = alloc_preg (cfg);
1502                 int iid_one_bit_reg = alloc_preg (cfg);
1503                 int iid_bit_reg = alloc_preg (cfg);
1504                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1505                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1506                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1507                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1508                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1509                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1510                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1511                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1512         } else {
1513                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1514                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1515         }
1516 #endif
1517 }
1518
1519 /* 
1520  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1521  * stored in "klass_reg" implements the interface "klass".
1522  */
1523 static void
1524 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1525 {
1526         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1527 }
1528
1529 /* 
1530  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1531  * stored in "vtable_reg" implements the interface "klass".
1532  */
1533 static void
1534 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1535 {
1536         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1537 }
1538
1539 /* 
1540  * Emit code which checks whenever the interface id of @klass is smaller than
1541  * than the value given by max_iid_reg.
1542 */
1543 static void
1544 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1545                                                  MonoBasicBlock *false_target)
1546 {
1547         if (cfg->compile_aot) {
1548                 int iid_reg = alloc_preg (cfg);
1549                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1550                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1551         }
1552         else
1553                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1554         if (false_target)
1555                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1556         else
1557                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1558 }
1559
1560 /* Same as above, but obtains max_iid from a vtable */
1561 static void
1562 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1563                                                                  MonoBasicBlock *false_target)
1564 {
1565         int max_iid_reg = alloc_preg (cfg);
1566                 
1567         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1568         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1569 }
1570
1571 /* Same as above, but obtains max_iid from a klass */
1572 static void
1573 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1574                                                                  MonoBasicBlock *false_target)
1575 {
1576         int max_iid_reg = alloc_preg (cfg);
1577
1578         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1579         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1580 }
1581
1582 static void
1583 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1584 {
1585         int idepth_reg = alloc_preg (cfg);
1586         int stypes_reg = alloc_preg (cfg);
1587         int stype = alloc_preg (cfg);
1588
1589         mono_class_setup_supertypes (klass);
1590
1591         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1592                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1593                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1594                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1595         }
1596         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1597         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1598         if (klass_ins) {
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1600         } else if (cfg->compile_aot) {
1601                 int const_reg = alloc_preg (cfg);
1602                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1604         } else {
1605                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1606         }
1607         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1608 }
1609
1610 static void
1611 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1612 {
1613         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1614 }
1615
1616 static void
1617 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1618 {
1619         int intf_reg = alloc_preg (cfg);
1620
1621         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1622         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1623         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1624         if (true_target)
1625                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1626         else
1627                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1628 }
1629
1630 /*
1631  * Variant of the above that takes a register to the class, not the vtable.
1632  */
1633 static void
1634 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1635 {
1636         int intf_bit_reg = alloc_preg (cfg);
1637
1638         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1639         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1640         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1641         if (true_target)
1642                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1643         else
1644                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1645 }
1646
1647 static inline void
1648 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1649 {
1650         if (klass_inst) {
1651                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1652         } else if (cfg->compile_aot) {
1653                 int const_reg = alloc_preg (cfg);
1654                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1655                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1656         } else {
1657                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1658         }
1659         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1660 }
1661
1662 static inline void
1663 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1664 {
1665         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1666 }
1667
1668 static inline void
1669 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1670 {
1671         if (cfg->compile_aot) {
1672                 int const_reg = alloc_preg (cfg);
1673                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1674                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1675         } else {
1676                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1677         }
1678         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1679 }
1680
1681 static void
1682 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1683         
1684 static void
1685 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1686 {
1687         if (klass->rank) {
1688                 int rank_reg = alloc_preg (cfg);
1689                 int eclass_reg = alloc_preg (cfg);
1690
1691                 g_assert (!klass_inst);
1692                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1693                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1694                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1695                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1696                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1697                 if (klass->cast_class == mono_defaults.object_class) {
1698                         int parent_reg = alloc_preg (cfg);
1699                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1700                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1701                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1702                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1703                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1704                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1705                 } else if (klass->cast_class == mono_defaults.enum_class) {
1706                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1707                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1708                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1709                 } else {
1710                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1711                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1712                 }
1713
1714                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1715                         /* Check that the object is a vector too */
1716                         int bounds_reg = alloc_preg (cfg);
1717                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1718                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1719                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1720                 }
1721         } else {
1722                 int idepth_reg = alloc_preg (cfg);
1723                 int stypes_reg = alloc_preg (cfg);
1724                 int stype = alloc_preg (cfg);
1725
1726                 mono_class_setup_supertypes (klass);
1727
1728                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1729                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1730                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1731                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1732                 }
1733                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1734                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1735                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1736         }
1737 }
1738
1739 static void
1740 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1741 {
1742         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1743 }
1744
1745 static void 
1746 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1747 {
1748         int val_reg;
1749
1750         g_assert (val == 0);
1751
1752         if (align == 0)
1753                 align = 4;
1754
1755         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1756                 switch (size) {
1757                 case 1:
1758                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1759                         return;
1760                 case 2:
1761                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1762                         return;
1763                 case 4:
1764                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1765                         return;
1766 #if SIZEOF_REGISTER == 8
1767                 case 8:
1768                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1769                         return;
1770 #endif
1771                 }
1772         }
1773
1774         val_reg = alloc_preg (cfg);
1775
1776         if (SIZEOF_REGISTER == 8)
1777                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1778         else
1779                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1780
1781         if (align < 4) {
1782                 /* This could be optimized further if neccesary */
1783                 while (size >= 1) {
1784                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1785                         offset += 1;
1786                         size -= 1;
1787                 }
1788                 return;
1789         }       
1790
1791 #if !NO_UNALIGNED_ACCESS
1792         if (SIZEOF_REGISTER == 8) {
1793                 if (offset % 8) {
1794                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1795                         offset += 4;
1796                         size -= 4;
1797                 }
1798                 while (size >= 8) {
1799                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1800                         offset += 8;
1801                         size -= 8;
1802                 }
1803         }       
1804 #endif
1805
1806         while (size >= 4) {
1807                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1808                 offset += 4;
1809                 size -= 4;
1810         }
1811         while (size >= 2) {
1812                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1813                 offset += 2;
1814                 size -= 2;
1815         }
1816         while (size >= 1) {
1817                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1818                 offset += 1;
1819                 size -= 1;
1820         }
1821 }
1822
1823 void 
1824 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1825 {
1826         int cur_reg;
1827
1828         if (align == 0)
1829                 align = 4;
1830
1831         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1832         g_assert (size < 10000);
1833
1834         if (align < 4) {
1835                 /* This could be optimized further if neccesary */
1836                 while (size >= 1) {
1837                         cur_reg = alloc_preg (cfg);
1838                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1839                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1840                         doffset += 1;
1841                         soffset += 1;
1842                         size -= 1;
1843                 }
1844         }
1845
1846 #if !NO_UNALIGNED_ACCESS
1847         if (SIZEOF_REGISTER == 8) {
1848                 while (size >= 8) {
1849                         cur_reg = alloc_preg (cfg);
1850                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1851                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1852                         doffset += 8;
1853                         soffset += 8;
1854                         size -= 8;
1855                 }
1856         }       
1857 #endif
1858
1859         while (size >= 4) {
1860                 cur_reg = alloc_preg (cfg);
1861                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1862                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1863                 doffset += 4;
1864                 soffset += 4;
1865                 size -= 4;
1866         }
1867         while (size >= 2) {
1868                 cur_reg = alloc_preg (cfg);
1869                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1870                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1871                 doffset += 2;
1872                 soffset += 2;
1873                 size -= 2;
1874         }
1875         while (size >= 1) {
1876                 cur_reg = alloc_preg (cfg);
1877                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1878                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1879                 doffset += 1;
1880                 soffset += 1;
1881                 size -= 1;
1882         }
1883 }
1884
1885 static void
1886 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1887 {
1888         MonoInst *ins, *c;
1889
1890         if (cfg->compile_aot) {
1891                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1892                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1893                 ins->sreg1 = sreg1;
1894                 ins->sreg2 = c->dreg;
1895                 MONO_ADD_INS (cfg->cbb, ins);
1896         } else {
1897                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1898                 ins->sreg1 = sreg1;
1899                 ins->inst_offset = mini_get_tls_offset (tls_key);
1900                 MONO_ADD_INS (cfg->cbb, ins);
1901         }
1902 }
1903
1904 /*
1905  * emit_push_lmf:
1906  *
1907  *   Emit IR to push the current LMF onto the LMF stack.
1908  */
1909 static void
1910 emit_push_lmf (MonoCompile *cfg)
1911 {
1912         /*
1913          * Emit IR to push the LMF:
1914          * lmf_addr = <lmf_addr from tls>
1915          * lmf->lmf_addr = lmf_addr
1916          * lmf->prev_lmf = *lmf_addr
1917          * *lmf_addr = lmf
1918          */
1919         int lmf_reg, prev_lmf_reg;
1920         MonoInst *ins, *lmf_ins;
1921
1922         if (!cfg->lmf_ir)
1923                 return;
1924
1925         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1926                 /* Load current lmf */
1927                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1928                 g_assert (lmf_ins);
1929                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1930                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1931                 lmf_reg = ins->dreg;
1932                 /* Save previous_lmf */
1933                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1934                 /* Set new LMF */
1935                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1936         } else {
1937                 /*
1938                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1939                  */
1940                 if (!cfg->lmf_addr_var)
1941                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1942
1943 #ifdef HOST_WIN32
1944                 ins = mono_get_jit_tls_intrinsic (cfg);
1945                 if (ins) {
1946                         int jit_tls_dreg = ins->dreg;
1947
1948                         MONO_ADD_INS (cfg->cbb, ins);
1949                         lmf_reg = alloc_preg (cfg);
1950                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, G_STRUCT_OFFSET (MonoJitTlsData, lmf));
1951                 } else {
1952                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1953                 }
1954 #else
1955                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1956                 if (lmf_ins) 
1957                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1958                 else
1959                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1960 #endif
1961                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1962
1963                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1964                 lmf_reg = ins->dreg;
1965
1966                 prev_lmf_reg = alloc_preg (cfg);
1967                 /* Save previous_lmf */
1968                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1969                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1970                 /* Set new lmf */
1971                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1972         }
1973 }
1974
1975 /*
1976  * emit_pop_lmf:
1977  *
1978  *   Emit IR to pop the current LMF from the LMF stack.
1979  */
1980 static void
1981 emit_pop_lmf (MonoCompile *cfg)
1982 {
1983         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1984         MonoInst *ins;
1985
1986         if (!cfg->lmf_ir)
1987                 return;
1988
1989         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1990         lmf_reg = ins->dreg;
1991
1992         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1993                 /* Load previous_lmf */
1994                 prev_lmf_reg = alloc_preg (cfg);
1995                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1996                 /* Set new LMF */
1997                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1998         } else {
1999                 /*
2000                  * Emit IR to pop the LMF:
2001                  * *(lmf->lmf_addr) = lmf->prev_lmf
2002                  */
2003                 /* This could be called before emit_push_lmf () */
2004                 if (!cfg->lmf_addr_var)
2005                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2006                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2007
2008                 prev_lmf_reg = alloc_preg (cfg);
2009                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2010                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2011         }
2012 }
2013
2014 static int
2015 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2016 {
2017         if (type->byref)
2018                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2019
2020 handle_enum:
2021         type = mini_get_basic_type_from_generic (gsctx, type);
2022         type = mini_replace_type (type);
2023         switch (type->type) {
2024         case MONO_TYPE_VOID:
2025                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2026         case MONO_TYPE_I1:
2027         case MONO_TYPE_U1:
2028         case MONO_TYPE_BOOLEAN:
2029         case MONO_TYPE_I2:
2030         case MONO_TYPE_U2:
2031         case MONO_TYPE_CHAR:
2032         case MONO_TYPE_I4:
2033         case MONO_TYPE_U4:
2034                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2035         case MONO_TYPE_I:
2036         case MONO_TYPE_U:
2037         case MONO_TYPE_PTR:
2038         case MONO_TYPE_FNPTR:
2039                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2040         case MONO_TYPE_CLASS:
2041         case MONO_TYPE_STRING:
2042         case MONO_TYPE_OBJECT:
2043         case MONO_TYPE_SZARRAY:
2044         case MONO_TYPE_ARRAY:    
2045                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2046         case MONO_TYPE_I8:
2047         case MONO_TYPE_U8:
2048                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2049         case MONO_TYPE_R4:
2050         case MONO_TYPE_R8:
2051                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2052         case MONO_TYPE_VALUETYPE:
2053                 if (type->data.klass->enumtype) {
2054                         type = mono_class_enum_basetype (type->data.klass);
2055                         goto handle_enum;
2056                 } else
2057                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2058         case MONO_TYPE_TYPEDBYREF:
2059                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2060         case MONO_TYPE_GENERICINST:
2061                 type = &type->data.generic_class->container_class->byval_arg;
2062                 goto handle_enum;
2063         case MONO_TYPE_VAR:
2064         case MONO_TYPE_MVAR:
2065                 /* gsharedvt */
2066                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2067         default:
2068                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2069         }
2070         return -1;
2071 }
2072
2073 /*
2074  * target_type_is_incompatible:
2075  * @cfg: MonoCompile context
2076  *
2077  * Check that the item @arg on the evaluation stack can be stored
2078  * in the target type (can be a local, or field, etc).
2079  * The cfg arg can be used to check if we need verification or just
2080  * validity checks.
2081  *
2082  * Returns: non-0 value if arg can't be stored on a target.
2083  */
2084 static int
2085 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2086 {
2087         MonoType *simple_type;
2088         MonoClass *klass;
2089
2090         target = mini_replace_type (target);
2091         if (target->byref) {
2092                 /* FIXME: check that the pointed to types match */
2093                 if (arg->type == STACK_MP)
2094                         return arg->klass != mono_class_from_mono_type (target);
2095                 if (arg->type == STACK_PTR)
2096                         return 0;
2097                 return 1;
2098         }
2099
2100         simple_type = mono_type_get_underlying_type (target);
2101         switch (simple_type->type) {
2102         case MONO_TYPE_VOID:
2103                 return 1;
2104         case MONO_TYPE_I1:
2105         case MONO_TYPE_U1:
2106         case MONO_TYPE_BOOLEAN:
2107         case MONO_TYPE_I2:
2108         case MONO_TYPE_U2:
2109         case MONO_TYPE_CHAR:
2110         case MONO_TYPE_I4:
2111         case MONO_TYPE_U4:
2112                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2113                         return 1;
2114                 return 0;
2115         case MONO_TYPE_PTR:
2116                 /* STACK_MP is needed when setting pinned locals */
2117                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2118                         return 1;
2119                 return 0;
2120         case MONO_TYPE_I:
2121         case MONO_TYPE_U:
2122         case MONO_TYPE_FNPTR:
2123                 /* 
2124                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2125                  * in native int. (#688008).
2126                  */
2127                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2128                         return 1;
2129                 return 0;
2130         case MONO_TYPE_CLASS:
2131         case MONO_TYPE_STRING:
2132         case MONO_TYPE_OBJECT:
2133         case MONO_TYPE_SZARRAY:
2134         case MONO_TYPE_ARRAY:    
2135                 if (arg->type != STACK_OBJ)
2136                         return 1;
2137                 /* FIXME: check type compatibility */
2138                 return 0;
2139         case MONO_TYPE_I8:
2140         case MONO_TYPE_U8:
2141                 if (arg->type != STACK_I8)
2142                         return 1;
2143                 return 0;
2144         case MONO_TYPE_R4:
2145         case MONO_TYPE_R8:
2146                 if (arg->type != STACK_R8)
2147                         return 1;
2148                 return 0;
2149         case MONO_TYPE_VALUETYPE:
2150                 if (arg->type != STACK_VTYPE)
2151                         return 1;
2152                 klass = mono_class_from_mono_type (simple_type);
2153                 if (klass != arg->klass)
2154                         return 1;
2155                 return 0;
2156         case MONO_TYPE_TYPEDBYREF:
2157                 if (arg->type != STACK_VTYPE)
2158                         return 1;
2159                 klass = mono_class_from_mono_type (simple_type);
2160                 if (klass != arg->klass)
2161                         return 1;
2162                 return 0;
2163         case MONO_TYPE_GENERICINST:
2164                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2165                         if (arg->type != STACK_VTYPE)
2166                                 return 1;
2167                         klass = mono_class_from_mono_type (simple_type);
2168                         if (klass != arg->klass)
2169                                 return 1;
2170                         return 0;
2171                 } else {
2172                         if (arg->type != STACK_OBJ)
2173                                 return 1;
2174                         /* FIXME: check type compatibility */
2175                         return 0;
2176                 }
2177         case MONO_TYPE_VAR:
2178         case MONO_TYPE_MVAR:
2179                 g_assert (cfg->generic_sharing_context);
2180                 if (mini_type_var_is_vt (cfg, simple_type)) {
2181                         if (arg->type != STACK_VTYPE)
2182                                 return 1;
2183                 } else {
2184                         if (arg->type != STACK_OBJ)
2185                                 return 1;
2186                 }
2187                 return 0;
2188         default:
2189                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2190         }
2191         return 1;
2192 }
2193
2194 /*
2195  * Prepare arguments for passing to a function call.
2196  * Return a non-zero value if the arguments can't be passed to the given
2197  * signature.
2198  * The type checks are not yet complete and some conversions may need
2199  * casts on 32 or 64 bit architectures.
2200  *
2201  * FIXME: implement this using target_type_is_incompatible ()
2202  */
2203 static int
2204 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2205 {
2206         MonoType *simple_type;
2207         int i;
2208
2209         if (sig->hasthis) {
2210                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2211                         return 1;
2212                 args++;
2213         }
2214         for (i = 0; i < sig->param_count; ++i) {
2215                 if (sig->params [i]->byref) {
2216                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2217                                 return 1;
2218                         continue;
2219                 }
2220                 simple_type = sig->params [i];
2221                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2222 handle_enum:
2223                 switch (simple_type->type) {
2224                 case MONO_TYPE_VOID:
2225                         return 1;
2226                         continue;
2227                 case MONO_TYPE_I1:
2228                 case MONO_TYPE_U1:
2229                 case MONO_TYPE_BOOLEAN:
2230                 case MONO_TYPE_I2:
2231                 case MONO_TYPE_U2:
2232                 case MONO_TYPE_CHAR:
2233                 case MONO_TYPE_I4:
2234                 case MONO_TYPE_U4:
2235                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2236                                 return 1;
2237                         continue;
2238                 case MONO_TYPE_I:
2239                 case MONO_TYPE_U:
2240                 case MONO_TYPE_PTR:
2241                 case MONO_TYPE_FNPTR:
2242                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2243                                 return 1;
2244                         continue;
2245                 case MONO_TYPE_CLASS:
2246                 case MONO_TYPE_STRING:
2247                 case MONO_TYPE_OBJECT:
2248                 case MONO_TYPE_SZARRAY:
2249                 case MONO_TYPE_ARRAY:    
2250                         if (args [i]->type != STACK_OBJ)
2251                                 return 1;
2252                         continue;
2253                 case MONO_TYPE_I8:
2254                 case MONO_TYPE_U8:
2255                         if (args [i]->type != STACK_I8)
2256                                 return 1;
2257                         continue;
2258                 case MONO_TYPE_R4:
2259                 case MONO_TYPE_R8:
2260                         if (args [i]->type != STACK_R8)
2261                                 return 1;
2262                         continue;
2263                 case MONO_TYPE_VALUETYPE:
2264                         if (simple_type->data.klass->enumtype) {
2265                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2266                                 goto handle_enum;
2267                         }
2268                         if (args [i]->type != STACK_VTYPE)
2269                                 return 1;
2270                         continue;
2271                 case MONO_TYPE_TYPEDBYREF:
2272                         if (args [i]->type != STACK_VTYPE)
2273                                 return 1;
2274                         continue;
2275                 case MONO_TYPE_GENERICINST:
2276                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2277                         goto handle_enum;
2278                 case MONO_TYPE_VAR:
2279                 case MONO_TYPE_MVAR:
2280                         /* gsharedvt */
2281                         if (args [i]->type != STACK_VTYPE)
2282                                 return 1;
2283                         continue;
2284                 default:
2285                         g_error ("unknown type 0x%02x in check_call_signature",
2286                                  simple_type->type);
2287                 }
2288         }
2289         return 0;
2290 }
2291
2292 static int
2293 callvirt_to_call (int opcode)
2294 {
2295         switch (opcode) {
2296         case OP_CALL_MEMBASE:
2297                 return OP_CALL;
2298         case OP_VOIDCALL_MEMBASE:
2299                 return OP_VOIDCALL;
2300         case OP_FCALL_MEMBASE:
2301                 return OP_FCALL;
2302         case OP_VCALL_MEMBASE:
2303                 return OP_VCALL;
2304         case OP_LCALL_MEMBASE:
2305                 return OP_LCALL;
2306         default:
2307                 g_assert_not_reached ();
2308         }
2309
2310         return -1;
2311 }
2312
2313 #ifdef MONO_ARCH_HAVE_IMT
2314 /* Either METHOD or IMT_ARG needs to be set */
2315 static void
2316 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2317 {
2318         int method_reg;
2319
2320         if (COMPILE_LLVM (cfg)) {
2321                 method_reg = alloc_preg (cfg);
2322
2323                 if (imt_arg) {
2324                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2325                 } else if (cfg->compile_aot) {
2326                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2327                 } else {
2328                         MonoInst *ins;
2329                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2330                         ins->inst_p0 = method;
2331                         ins->dreg = method_reg;
2332                         MONO_ADD_INS (cfg->cbb, ins);
2333                 }
2334
2335 #ifdef ENABLE_LLVM
2336                 call->imt_arg_reg = method_reg;
2337 #endif
2338 #ifdef MONO_ARCH_IMT_REG
2339         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2340 #else
2341         /* Need this to keep the IMT arg alive */
2342         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2343 #endif
2344                 return;
2345         }
2346
2347 #ifdef MONO_ARCH_IMT_REG
2348         method_reg = alloc_preg (cfg);
2349
2350         if (imt_arg) {
2351                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2352         } else if (cfg->compile_aot) {
2353                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2354         } else {
2355                 MonoInst *ins;
2356                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2357                 ins->inst_p0 = method;
2358                 ins->dreg = method_reg;
2359                 MONO_ADD_INS (cfg->cbb, ins);
2360         }
2361
2362         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2363 #else
2364         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2365 #endif
2366 }
2367 #endif
2368
2369 static MonoJumpInfo *
2370 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2371 {
2372         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2373
2374         ji->ip.i = ip;
2375         ji->type = type;
2376         ji->data.target = target;
2377
2378         return ji;
2379 }
2380
2381 static int
2382 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2383 {
2384         if (cfg->generic_sharing_context)
2385                 return mono_class_check_context_used (klass);
2386         else
2387                 return 0;
2388 }
2389
2390 static int
2391 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2392 {
2393         if (cfg->generic_sharing_context)
2394                 return mono_method_check_context_used (method);
2395         else
2396                 return 0;
2397 }
2398
2399 /*
2400  * check_method_sharing:
2401  *
2402  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2403  */
2404 static void
2405 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2406 {
2407         gboolean pass_vtable = FALSE;
2408         gboolean pass_mrgctx = FALSE;
2409
2410         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2411                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2412                 gboolean sharable = FALSE;
2413
2414                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2415                         sharable = TRUE;
2416                 } else {
2417                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2418                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2419                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2420
2421                         sharable = sharing_enabled && context_sharable;
2422                 }
2423
2424                 /*
2425                  * Pass vtable iff target method might
2426                  * be shared, which means that sharing
2427                  * is enabled for its class and its
2428                  * context is sharable (and it's not a
2429                  * generic method).
2430                  */
2431                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2432                         pass_vtable = TRUE;
2433         }
2434
2435         if (mini_method_get_context (cmethod) &&
2436                 mini_method_get_context (cmethod)->method_inst) {
2437                 g_assert (!pass_vtable);
2438
2439                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2440                         pass_mrgctx = TRUE;
2441                 } else {
2442                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2443                         MonoGenericContext *context = mini_method_get_context (cmethod);
2444                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2445
2446                         if (sharing_enabled && context_sharable)
2447                                 pass_mrgctx = TRUE;
2448                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2449                                 pass_mrgctx = TRUE;
2450                 }
2451         }
2452
2453         if (out_pass_vtable)
2454                 *out_pass_vtable = pass_vtable;
2455         if (out_pass_mrgctx)
2456                 *out_pass_mrgctx = pass_mrgctx;
2457 }
2458
2459 inline static MonoCallInst *
2460 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2461                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2462 {
2463         MonoType *sig_ret;
2464         MonoCallInst *call;
2465 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2466         int i;
2467 #endif
2468
2469         if (tail)
2470                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2471         else
2472                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2473
2474         call->args = args;
2475         call->signature = sig;
2476         call->rgctx_reg = rgctx;
2477         sig_ret = mini_replace_type (sig->ret);
2478
2479         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2480
2481         if (tail) {
2482                 if (mini_type_is_vtype (cfg, sig_ret)) {
2483                         call->vret_var = cfg->vret_addr;
2484                         //g_assert_not_reached ();
2485                 }
2486         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2487                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2488                 MonoInst *loada;
2489
2490                 temp->backend.is_pinvoke = sig->pinvoke;
2491
2492                 /*
2493                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2494                  * address of return value to increase optimization opportunities.
2495                  * Before vtype decomposition, the dreg of the call ins itself represents the
2496                  * fact the call modifies the return value. After decomposition, the call will
2497                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2498                  * will be transformed into an LDADDR.
2499                  */
2500                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2501                 loada->dreg = alloc_preg (cfg);
2502                 loada->inst_p0 = temp;
2503                 /* We reference the call too since call->dreg could change during optimization */
2504                 loada->inst_p1 = call;
2505                 MONO_ADD_INS (cfg->cbb, loada);
2506
2507                 call->inst.dreg = temp->dreg;
2508
2509                 call->vret_var = loada;
2510         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2511                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2512
2513 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2514         if (COMPILE_SOFT_FLOAT (cfg)) {
2515                 /* 
2516                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2517                  * an icall, but that cannot be done during the call sequence since it would clobber
2518                  * the call registers + the stack. So we do it before emitting the call.
2519                  */
2520                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2521                         MonoType *t;
2522                         MonoInst *in = call->args [i];
2523
2524                         if (i >= sig->hasthis)
2525                                 t = sig->params [i - sig->hasthis];
2526                         else
2527                                 t = &mono_defaults.int_class->byval_arg;
2528                         t = mono_type_get_underlying_type (t);
2529
2530                         if (!t->byref && t->type == MONO_TYPE_R4) {
2531                                 MonoInst *iargs [1];
2532                                 MonoInst *conv;
2533
2534                                 iargs [0] = in;
2535                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2536
2537                                 /* The result will be in an int vreg */
2538                                 call->args [i] = conv;
2539                         }
2540                 }
2541         }
2542 #endif
2543
2544         call->need_unbox_trampoline = unbox_trampoline;
2545
2546 #ifdef ENABLE_LLVM
2547         if (COMPILE_LLVM (cfg))
2548                 mono_llvm_emit_call (cfg, call);
2549         else
2550                 mono_arch_emit_call (cfg, call);
2551 #else
2552         mono_arch_emit_call (cfg, call);
2553 #endif
2554
2555         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2556         cfg->flags |= MONO_CFG_HAS_CALLS;
2557         
2558         return call;
2559 }
2560
2561 static void
2562 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2563 {
2564 #ifdef MONO_ARCH_RGCTX_REG
2565         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2566         cfg->uses_rgctx_reg = TRUE;
2567         call->rgctx_reg = TRUE;
2568 #ifdef ENABLE_LLVM
2569         call->rgctx_arg_reg = rgctx_reg;
2570 #endif
2571 #else
2572         NOT_IMPLEMENTED;
2573 #endif
2574 }       
2575
2576 inline static MonoInst*
2577 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2578 {
2579         MonoCallInst *call;
2580         MonoInst *ins;
2581         int rgctx_reg = -1;
2582         gboolean check_sp = FALSE;
2583
2584         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2585                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2586
2587                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2588                         check_sp = TRUE;
2589         }
2590
2591         if (rgctx_arg) {
2592                 rgctx_reg = mono_alloc_preg (cfg);
2593                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2594         }
2595
2596         if (check_sp) {
2597                 if (!cfg->stack_inbalance_var)
2598                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2599
2600                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2601                 ins->dreg = cfg->stack_inbalance_var->dreg;
2602                 MONO_ADD_INS (cfg->cbb, ins);
2603         }
2604
2605         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2606
2607         call->inst.sreg1 = addr->dreg;
2608
2609         if (imt_arg)
2610                 emit_imt_argument (cfg, call, NULL, imt_arg);
2611
2612         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2613
2614         if (check_sp) {
2615                 int sp_reg;
2616
2617                 sp_reg = mono_alloc_preg (cfg);
2618
2619                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2620                 ins->dreg = sp_reg;
2621                 MONO_ADD_INS (cfg->cbb, ins);
2622
2623                 /* Restore the stack so we don't crash when throwing the exception */
2624                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2625                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2626                 MONO_ADD_INS (cfg->cbb, ins);
2627
2628                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2629                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2630         }
2631
2632         if (rgctx_arg)
2633                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2634
2635         return (MonoInst*)call;
2636 }
2637
2638 static MonoInst*
2639 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2640
2641 static MonoInst*
2642 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2643 static MonoInst*
2644 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2645
2646 static MonoInst*
2647 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2648                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2649 {
2650 #ifndef DISABLE_REMOTING
2651         gboolean might_be_remote = FALSE;
2652 #endif
2653         gboolean virtual = this != NULL;
2654         gboolean enable_for_aot = TRUE;
2655         int context_used;
2656         MonoCallInst *call;
2657         int rgctx_reg = 0;
2658         gboolean need_unbox_trampoline;
2659
2660         if (!sig)
2661                 sig = mono_method_signature (method);
2662
2663         if (rgctx_arg) {
2664                 rgctx_reg = mono_alloc_preg (cfg);
2665                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2666         }
2667
2668         if (method->string_ctor) {
2669                 /* Create the real signature */
2670                 /* FIXME: Cache these */
2671                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2672                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2673
2674                 sig = ctor_sig;
2675         }
2676
2677         context_used = mini_method_check_context_used (cfg, method);
2678
2679 #ifndef DISABLE_REMOTING
2680         might_be_remote = this && sig->hasthis &&
2681                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2682                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2683
2684         if (might_be_remote && context_used) {
2685                 MonoInst *addr;
2686
2687                 g_assert (cfg->generic_sharing_context);
2688
2689                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2690
2691                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2692         }
2693 #endif
2694
2695         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2696
2697         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2698
2699 #ifndef DISABLE_REMOTING
2700         if (might_be_remote)
2701                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2702         else
2703 #endif
2704                 call->method = method;
2705         call->inst.flags |= MONO_INST_HAS_METHOD;
2706         call->inst.inst_left = this;
2707         call->tail_call = tail;
2708
2709         if (virtual) {
2710                 int vtable_reg, slot_reg, this_reg;
2711                 int offset;
2712
2713                 this_reg = this->dreg;
2714
2715                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2716                         MonoInst *dummy_use;
2717
2718                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2719
2720                         /* Make a call to delegate->invoke_impl */
2721                         call->inst.inst_basereg = this_reg;
2722                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2723                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2724
2725                         /* We must emit a dummy use here because the delegate trampoline will
2726                         replace the 'this' argument with the delegate target making this activation
2727                         no longer a root for the delegate.
2728                         This is an issue for delegates that target collectible code such as dynamic
2729                         methods of GC'able assemblies.
2730
2731                         For a test case look into #667921.
2732
2733                         FIXME: a dummy use is not the best way to do it as the local register allocator
2734                         will put it on a caller save register and spil it around the call. 
2735                         Ideally, we would either put it on a callee save register or only do the store part.  
2736                          */
2737                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2738
2739                         return (MonoInst*)call;
2740                 }
2741
2742                 if ((!cfg->compile_aot || enable_for_aot) && 
2743                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2744                          (MONO_METHOD_IS_FINAL (method) &&
2745                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2746                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2747                         /* 
2748                          * the method is not virtual, we just need to ensure this is not null
2749                          * and then we can call the method directly.
2750                          */
2751 #ifndef DISABLE_REMOTING
2752                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2753                                 /* 
2754                                  * The check above ensures method is not gshared, this is needed since
2755                                  * gshared methods can't have wrappers.
2756                                  */
2757                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2758                         }
2759 #endif
2760
2761                         if (!method->string_ctor)
2762                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2763
2764                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2765                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2766                         /*
2767                          * the method is virtual, but we can statically dispatch since either
2768                          * it's class or the method itself are sealed.
2769                          * But first we need to ensure it's not a null reference.
2770                          */
2771                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2772
2773                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2774                 } else {
2775                         vtable_reg = alloc_preg (cfg);
2776                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2777                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2778                                 slot_reg = -1;
2779 #ifdef MONO_ARCH_HAVE_IMT
2780                                 if (mono_use_imt) {
2781                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2782                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2783                                         slot_reg = vtable_reg;
2784                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2785                                 }
2786 #endif
2787                                 if (slot_reg == -1) {
2788                                         slot_reg = alloc_preg (cfg);
2789                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2790                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2791                                 }
2792                         } else {
2793                                 slot_reg = vtable_reg;
2794                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2795                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2796 #ifdef MONO_ARCH_HAVE_IMT
2797                                 if (imt_arg) {
2798                                         g_assert (mono_method_signature (method)->generic_param_count);
2799                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2800                                 }
2801 #endif
2802                         }
2803
2804                         call->inst.sreg1 = slot_reg;
2805                         call->inst.inst_offset = offset;
2806                         call->virtual = TRUE;
2807                 }
2808         }
2809
2810         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2811
2812         if (rgctx_arg)
2813                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2814
2815         return (MonoInst*)call;
2816 }
2817
2818 MonoInst*
2819 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2820 {
2821         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2822 }
2823
2824 MonoInst*
2825 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2826                                            MonoInst **args)
2827 {
2828         MonoCallInst *call;
2829
2830         g_assert (sig);
2831
2832         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2833         call->fptr = func;
2834
2835         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2836
2837         return (MonoInst*)call;
2838 }
2839
2840 MonoInst*
2841 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2842 {
2843         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2844
2845         g_assert (info);
2846
2847         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2848 }
2849
2850 /*
2851  * mono_emit_abs_call:
2852  *
2853  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2854  */
2855 inline static MonoInst*
2856 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2857                                         MonoMethodSignature *sig, MonoInst **args)
2858 {
2859         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2860         MonoInst *ins;
2861
2862         /* 
2863          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2864          * handle it.
2865          */
2866         if (cfg->abs_patches == NULL)
2867                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2868         g_hash_table_insert (cfg->abs_patches, ji, ji);
2869         ins = mono_emit_native_call (cfg, ji, sig, args);
2870         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2871         return ins;
2872 }
2873  
2874 static MonoInst*
2875 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2876 {
2877         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2878                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2879                         int widen_op = -1;
2880
2881                         /* 
2882                          * Native code might return non register sized integers 
2883                          * without initializing the upper bits.
2884                          */
2885                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2886                         case OP_LOADI1_MEMBASE:
2887                                 widen_op = OP_ICONV_TO_I1;
2888                                 break;
2889                         case OP_LOADU1_MEMBASE:
2890                                 widen_op = OP_ICONV_TO_U1;
2891                                 break;
2892                         case OP_LOADI2_MEMBASE:
2893                                 widen_op = OP_ICONV_TO_I2;
2894                                 break;
2895                         case OP_LOADU2_MEMBASE:
2896                                 widen_op = OP_ICONV_TO_U2;
2897                                 break;
2898                         default:
2899                                 break;
2900                         }
2901
2902                         if (widen_op != -1) {
2903                                 int dreg = alloc_preg (cfg);
2904                                 MonoInst *widen;
2905
2906                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2907                                 widen->type = ins->type;
2908                                 ins = widen;
2909                         }
2910                 }
2911         }
2912
2913         return ins;
2914 }
2915
2916 static MonoMethod*
2917 get_memcpy_method (void)
2918 {
2919         static MonoMethod *memcpy_method = NULL;
2920         if (!memcpy_method) {
2921                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2922                 if (!memcpy_method)
2923                         g_error ("Old corlib found. Install a new one");
2924         }
2925         return memcpy_method;
2926 }
2927
2928 static void
2929 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2930 {
2931         MonoClassField *field;
2932         gpointer iter = NULL;
2933
2934         while ((field = mono_class_get_fields (klass, &iter))) {
2935                 int foffset;
2936
2937                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2938                         continue;
2939                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2940                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2941                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2942                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2943                 } else {
2944                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2945                         if (field_class->has_references)
2946                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2947                 }
2948         }
2949 }
2950
2951 static void
2952 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2953 {
2954         int card_table_shift_bits;
2955         gpointer card_table_mask;
2956         guint8 *card_table;
2957         MonoInst *dummy_use;
2958         int nursery_shift_bits;
2959         size_t nursery_size;
2960         gboolean has_card_table_wb = FALSE;
2961
2962         if (!cfg->gen_write_barriers)
2963                 return;
2964
2965         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2966
2967         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2968
2969 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2970         has_card_table_wb = TRUE;
2971 #endif
2972
2973         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2974                 MonoInst *wbarrier;
2975
2976                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2977                 wbarrier->sreg1 = ptr->dreg;
2978                 wbarrier->sreg2 = value->dreg;
2979                 MONO_ADD_INS (cfg->cbb, wbarrier);
2980         } else if (card_table) {
2981                 int offset_reg = alloc_preg (cfg);
2982                 int card_reg  = alloc_preg (cfg);
2983                 MonoInst *ins;
2984
2985                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2986                 if (card_table_mask)
2987                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2988
2989                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2990                  * IMM's larger than 32bits.
2991                  */
2992                 if (cfg->compile_aot) {
2993                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2994                 } else {
2995                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2996                         ins->inst_p0 = card_table;
2997                         ins->dreg = card_reg;
2998                         MONO_ADD_INS (cfg->cbb, ins);
2999                 }
3000
3001                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3002                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3003         } else {
3004                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3005                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3006         }
3007
3008         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3009 }
3010
3011 static gboolean
3012 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3013 {
3014         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3015         unsigned need_wb = 0;
3016
3017         if (align == 0)
3018                 align = 4;
3019
3020         /*types with references can't have alignment smaller than sizeof(void*) */
3021         if (align < SIZEOF_VOID_P)
3022                 return FALSE;
3023
3024         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3025         if (size > 32 * SIZEOF_VOID_P)
3026                 return FALSE;
3027
3028         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3029
3030         /* We don't unroll more than 5 stores to avoid code bloat. */
3031         if (size > 5 * SIZEOF_VOID_P) {
3032                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3033                 size += (SIZEOF_VOID_P - 1);
3034                 size &= ~(SIZEOF_VOID_P - 1);
3035
3036                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3037                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3038                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3039                 return TRUE;
3040         }
3041
3042         destreg = iargs [0]->dreg;
3043         srcreg = iargs [1]->dreg;
3044         offset = 0;
3045
3046         dest_ptr_reg = alloc_preg (cfg);
3047         tmp_reg = alloc_preg (cfg);
3048
3049         /*tmp = dreg*/
3050         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3051
3052         while (size >= SIZEOF_VOID_P) {
3053                 MonoInst *load_inst;
3054                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3055                 load_inst->dreg = tmp_reg;
3056                 load_inst->inst_basereg = srcreg;
3057                 load_inst->inst_offset = offset;
3058                 MONO_ADD_INS (cfg->cbb, load_inst);
3059
3060                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3061
3062                 if (need_wb & 0x1)
3063                         emit_write_barrier (cfg, iargs [0], load_inst);
3064
3065                 offset += SIZEOF_VOID_P;
3066                 size -= SIZEOF_VOID_P;
3067                 need_wb >>= 1;
3068
3069                 /*tmp += sizeof (void*)*/
3070                 if (size >= SIZEOF_VOID_P) {
3071                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3072                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3073                 }
3074         }
3075
3076         /* Those cannot be references since size < sizeof (void*) */
3077         while (size >= 4) {
3078                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3079                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3080                 offset += 4;
3081                 size -= 4;
3082         }
3083
3084         while (size >= 2) {
3085                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3086                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3087                 offset += 2;
3088                 size -= 2;
3089         }
3090
3091         while (size >= 1) {
3092                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3093                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3094                 offset += 1;
3095                 size -= 1;
3096         }
3097
3098         return TRUE;
3099 }
3100
3101 /*
3102  * Emit code to copy a valuetype of type @klass whose address is stored in
3103  * @src->dreg to memory whose address is stored at @dest->dreg.
3104  */
3105 void
3106 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3107 {
3108         MonoInst *iargs [4];
3109         int context_used, n;
3110         guint32 align = 0;
3111         MonoMethod *memcpy_method;
3112         MonoInst *size_ins = NULL;
3113         MonoInst *memcpy_ins = NULL;
3114
3115         g_assert (klass);
3116         /*
3117          * This check breaks with spilled vars... need to handle it during verification anyway.
3118          * g_assert (klass && klass == src->klass && klass == dest->klass);
3119          */
3120
3121         if (mini_is_gsharedvt_klass (cfg, klass)) {
3122                 g_assert (!native);
3123                 context_used = mini_class_check_context_used (cfg, klass);
3124                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3125                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3126         }
3127
3128         if (native)
3129                 n = mono_class_native_size (klass, &align);
3130         else
3131                 n = mono_class_value_size (klass, &align);
3132
3133         /* if native is true there should be no references in the struct */
3134         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3135                 /* Avoid barriers when storing to the stack */
3136                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3137                           (dest->opcode == OP_LDADDR))) {
3138                         int context_used;
3139
3140                         iargs [0] = dest;
3141                         iargs [1] = src;
3142
3143                         context_used = mini_class_check_context_used (cfg, klass);
3144
3145                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3146                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3147                                 return;
3148                         } else if (context_used) {
3149                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3150                         }  else {
3151                                 if (cfg->compile_aot) {
3152                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3153                                 } else {
3154                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3155                                         mono_class_compute_gc_descriptor (klass);
3156                                 }
3157                         }
3158
3159                         if (size_ins)
3160                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3161                         else
3162                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3163                         return;
3164                 }
3165         }
3166
3167         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3168                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3169                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3170         } else {
3171                 iargs [0] = dest;
3172                 iargs [1] = src;
3173                 if (size_ins)
3174                         iargs [2] = size_ins;
3175                 else
3176                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3177                 
3178                 memcpy_method = get_memcpy_method ();
3179                 if (memcpy_ins)
3180                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3181                 else
3182                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3183         }
3184 }
3185
3186 static MonoMethod*
3187 get_memset_method (void)
3188 {
3189         static MonoMethod *memset_method = NULL;
3190         if (!memset_method) {
3191                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3192                 if (!memset_method)
3193                         g_error ("Old corlib found. Install a new one");
3194         }
3195         return memset_method;
3196 }
3197
3198 void
3199 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3200 {
3201         MonoInst *iargs [3];
3202         int n, context_used;
3203         guint32 align;
3204         MonoMethod *memset_method;
3205         MonoInst *size_ins = NULL;
3206         MonoInst *bzero_ins = NULL;
3207         static MonoMethod *bzero_method;
3208
3209         /* FIXME: Optimize this for the case when dest is an LDADDR */
3210
3211         mono_class_init (klass);
3212         if (mini_is_gsharedvt_klass (cfg, klass)) {
3213                 context_used = mini_class_check_context_used (cfg, klass);
3214                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3215                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3216                 if (!bzero_method)
3217                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3218                 g_assert (bzero_method);
3219                 iargs [0] = dest;
3220                 iargs [1] = size_ins;
3221                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3222                 return;
3223         }
3224
3225         n = mono_class_value_size (klass, &align);
3226
3227         if (n <= sizeof (gpointer) * 5) {
3228                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3229         }
3230         else {
3231                 memset_method = get_memset_method ();
3232                 iargs [0] = dest;
3233                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3234                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3235                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3236         }
3237 }
3238
3239 static MonoInst*
3240 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3241 {
3242         MonoInst *this = NULL;
3243
3244         g_assert (cfg->generic_sharing_context);
3245
3246         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3247                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3248                         !method->klass->valuetype)
3249                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3250
3251         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3252                 MonoInst *mrgctx_loc, *mrgctx_var;
3253
3254                 g_assert (!this);
3255                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3256
3257                 mrgctx_loc = mono_get_vtable_var (cfg);
3258                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3259
3260                 return mrgctx_var;
3261         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3262                 MonoInst *vtable_loc, *vtable_var;
3263
3264                 g_assert (!this);
3265
3266                 vtable_loc = mono_get_vtable_var (cfg);
3267                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3268
3269                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3270                         MonoInst *mrgctx_var = vtable_var;
3271                         int vtable_reg;
3272
3273                         vtable_reg = alloc_preg (cfg);
3274                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3275                         vtable_var->type = STACK_PTR;
3276                 }
3277
3278                 return vtable_var;
3279         } else {
3280                 MonoInst *ins;
3281                 int vtable_reg;
3282         
3283                 vtable_reg = alloc_preg (cfg);
3284                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3285                 return ins;
3286         }
3287 }
3288
3289 static MonoJumpInfoRgctxEntry *
3290 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3291 {
3292         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3293         res->method = method;
3294         res->in_mrgctx = in_mrgctx;
3295         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3296         res->data->type = patch_type;
3297         res->data->data.target = patch_data;
3298         res->info_type = info_type;
3299
3300         return res;
3301 }
3302
3303 static inline MonoInst*
3304 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3305 {
3306         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3307 }
3308
3309 static MonoInst*
3310 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3311                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3312 {
3313         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);
3314         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3315
3316         return emit_rgctx_fetch (cfg, rgctx, entry);
3317 }
3318
3319 static MonoInst*
3320 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3321                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3322 {
3323         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);
3324         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3325
3326         return emit_rgctx_fetch (cfg, rgctx, entry);
3327 }
3328
3329 static MonoInst*
3330 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3331                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3332 {
3333         MonoJumpInfoGSharedVtCall *call_info;
3334         MonoJumpInfoRgctxEntry *entry;
3335         MonoInst *rgctx;
3336
3337         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3338         call_info->sig = sig;
3339         call_info->method = cmethod;
3340
3341         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);
3342         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3343
3344         return emit_rgctx_fetch (cfg, rgctx, entry);
3345 }
3346
3347
3348 static MonoInst*
3349 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3350                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3351 {
3352         MonoJumpInfoRgctxEntry *entry;
3353         MonoInst *rgctx;
3354
3355         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);
3356         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3357
3358         return emit_rgctx_fetch (cfg, rgctx, entry);
3359 }
3360
3361 /*
3362  * emit_get_rgctx_method:
3363  *
3364  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3365  * normal constants, else emit a load from the rgctx.
3366  */
3367 static MonoInst*
3368 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3369                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3370 {
3371         if (!context_used) {
3372                 MonoInst *ins;
3373
3374                 switch (rgctx_type) {
3375                 case MONO_RGCTX_INFO_METHOD:
3376                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3377                         return ins;
3378                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3379                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3380                         return ins;
3381                 default:
3382                         g_assert_not_reached ();
3383                 }
3384         } else {
3385                 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);
3386                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3387
3388                 return emit_rgctx_fetch (cfg, rgctx, entry);
3389         }
3390 }
3391
3392 static MonoInst*
3393 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3394                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3395 {
3396         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);
3397         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3398
3399         return emit_rgctx_fetch (cfg, rgctx, entry);
3400 }
3401
3402 static int
3403 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3404 {
3405         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3406         MonoRuntimeGenericContextInfoTemplate *template;
3407         int i, idx;
3408
3409         g_assert (info);
3410
3411         for (i = 0; i < info->num_entries; ++i) {
3412                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3413
3414                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3415                         return i;
3416         }
3417
3418         if (info->num_entries == info->count_entries) {
3419                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3420                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3421
3422                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3423
3424                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3425                 info->entries = new_entries;
3426                 info->count_entries = new_count_entries;
3427         }
3428
3429         idx = info->num_entries;
3430         template = &info->entries [idx];
3431         template->info_type = rgctx_type;
3432         template->data = data;
3433
3434         info->num_entries ++;
3435
3436         return idx;
3437 }
3438
3439 /*
3440  * emit_get_gsharedvt_info:
3441  *
3442  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3443  */
3444 static MonoInst*
3445 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3446 {
3447         MonoInst *ins;
3448         int idx, dreg;
3449
3450         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3451         /* Load info->entries [idx] */
3452         dreg = alloc_preg (cfg);
3453         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3454
3455         return ins;
3456 }
3457
3458 static MonoInst*
3459 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3460 {
3461         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3462 }
3463
3464 /*
3465  * On return the caller must check @klass for load errors.
3466  */
3467 static void
3468 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3469 {
3470         MonoInst *vtable_arg;
3471         MonoCallInst *call;
3472         int context_used;
3473
3474         context_used = mini_class_check_context_used (cfg, klass);
3475
3476         if (context_used) {
3477                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3478                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3479         } else {
3480                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3481
3482                 if (!vtable)
3483                         return;
3484                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3485         }
3486
3487         if (COMPILE_LLVM (cfg))
3488                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3489         else
3490                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3491 #ifdef MONO_ARCH_VTABLE_REG
3492         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3493         cfg->uses_vtable_reg = TRUE;
3494 #else
3495         NOT_IMPLEMENTED;
3496 #endif
3497 }
3498
3499 static void
3500 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3501 {
3502         MonoInst *ins;
3503
3504         if (cfg->gen_seq_points && cfg->method == method) {
3505                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3506                 if (nonempty_stack)
3507                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3508                 MONO_ADD_INS (cfg->cbb, ins);
3509         }
3510 }
3511
3512 static void
3513 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3514 {
3515         if (mini_get_debug_options ()->better_cast_details) {
3516                 int to_klass_reg = alloc_preg (cfg);
3517                 int vtable_reg = alloc_preg (cfg);
3518                 int klass_reg = alloc_preg (cfg);
3519                 MonoBasicBlock *is_null_bb = NULL;
3520                 MonoInst *tls_get;
3521
3522                 if (null_check) {
3523                         NEW_BBLOCK (cfg, is_null_bb);
3524
3525                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3526                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3527                 }
3528
3529                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3530                 if (!tls_get) {
3531                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3532                         exit (1);
3533                 }
3534
3535                 MONO_ADD_INS (cfg->cbb, tls_get);
3536                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3537                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3538
3539                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3540                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3541                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3542
3543                 if (null_check) {
3544                         MONO_START_BB (cfg, is_null_bb);
3545                         if (out_bblock)
3546                                 *out_bblock = cfg->cbb;
3547                 }
3548         }
3549 }
3550
3551 static void
3552 reset_cast_details (MonoCompile *cfg)
3553 {
3554         /* Reset the variables holding the cast details */
3555         if (mini_get_debug_options ()->better_cast_details) {
3556                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3557
3558                 MONO_ADD_INS (cfg->cbb, tls_get);
3559                 /* It is enough to reset the from field */
3560                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3561         }
3562 }
3563
3564 /*
3565  * On return the caller must check @array_class for load errors
3566  */
3567 static void
3568 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3569 {
3570         int vtable_reg = alloc_preg (cfg);
3571         int context_used;
3572
3573         context_used = mini_class_check_context_used (cfg, array_class);
3574
3575         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3576
3577         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3578
3579         if (cfg->opt & MONO_OPT_SHARED) {
3580                 int class_reg = alloc_preg (cfg);
3581                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3582                 if (cfg->compile_aot) {
3583                         int klass_reg = alloc_preg (cfg);
3584                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3585                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3586                 } else {
3587                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3588                 }
3589         } else if (context_used) {
3590                 MonoInst *vtable_ins;
3591
3592                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3593                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3594         } else {
3595                 if (cfg->compile_aot) {
3596                         int vt_reg;
3597                         MonoVTable *vtable;
3598
3599                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3600                                 return;
3601                         vt_reg = alloc_preg (cfg);
3602                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3603                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3604                 } else {
3605                         MonoVTable *vtable;
3606                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3607                                 return;
3608                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3609                 }
3610         }
3611         
3612         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3613
3614         reset_cast_details (cfg);
3615 }
3616
3617 /**
3618  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3619  * generic code is generated.
3620  */
3621 static MonoInst*
3622 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3623 {
3624         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3625
3626         if (context_used) {
3627                 MonoInst *rgctx, *addr;
3628
3629                 /* FIXME: What if the class is shared?  We might not
3630                    have to get the address of the method from the
3631                    RGCTX. */
3632                 addr = emit_get_rgctx_method (cfg, context_used, method,
3633                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3634
3635                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3636
3637                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3638         } else {
3639                 gboolean pass_vtable, pass_mrgctx;
3640                 MonoInst *rgctx_arg = NULL;
3641
3642                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3643                 g_assert (!pass_mrgctx);
3644
3645                 if (pass_vtable) {
3646                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3647
3648                         g_assert (vtable);
3649                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3650                 }
3651
3652                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3653         }
3654 }
3655
3656 static MonoInst*
3657 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3658 {
3659         MonoInst *add;
3660         int obj_reg;
3661         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3662         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3663         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3664         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3665
3666         obj_reg = sp [0]->dreg;
3667         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3668         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3669
3670         /* FIXME: generics */
3671         g_assert (klass->rank == 0);
3672                         
3673         // Check rank == 0
3674         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3675         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3676
3677         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3678         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3679
3680         if (context_used) {
3681                 MonoInst *element_class;
3682
3683                 /* This assertion is from the unboxcast insn */
3684                 g_assert (klass->rank == 0);
3685
3686                 element_class = emit_get_rgctx_klass (cfg, context_used,
3687                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3688
3689                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3690                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3691         } else {
3692                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3693                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3694                 reset_cast_details (cfg);
3695         }
3696
3697         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3698         MONO_ADD_INS (cfg->cbb, add);
3699         add->type = STACK_MP;
3700         add->klass = klass;
3701
3702         return add;
3703 }
3704
3705 static MonoInst*
3706 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3707 {
3708         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3709         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3710         MonoInst *ins;
3711         int dreg, addr_reg;
3712
3713         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3714
3715         /* obj */
3716         args [0] = obj;
3717
3718         /* klass */
3719         args [1] = klass_inst;
3720
3721         /* CASTCLASS */
3722         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3723
3724         NEW_BBLOCK (cfg, is_ref_bb);
3725         NEW_BBLOCK (cfg, is_nullable_bb);
3726         NEW_BBLOCK (cfg, end_bb);
3727         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3728         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3729         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3730
3731         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3732         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3733
3734         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3735         addr_reg = alloc_dreg (cfg, STACK_MP);
3736
3737         /* Non-ref case */
3738         /* UNBOX */
3739         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3740         MONO_ADD_INS (cfg->cbb, addr);
3741
3742         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3743
3744         /* Ref case */
3745         MONO_START_BB (cfg, is_ref_bb);
3746
3747         /* Save the ref to a temporary */
3748         dreg = alloc_ireg (cfg);
3749         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3750         addr->dreg = addr_reg;
3751         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3752         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3753
3754         /* Nullable case */
3755         MONO_START_BB (cfg, is_nullable_bb);
3756
3757         {
3758                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3759                 MonoInst *unbox_call;
3760                 MonoMethodSignature *unbox_sig;
3761                 MonoInst *var;
3762
3763                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3764
3765                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3766                 unbox_sig->ret = &klass->byval_arg;
3767                 unbox_sig->param_count = 1;
3768                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3769                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3770
3771                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3772                 addr->dreg = addr_reg;
3773         }
3774
3775         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3776
3777         /* End */
3778         MONO_START_BB (cfg, end_bb);
3779
3780         /* LDOBJ */
3781         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3782
3783         *out_cbb = cfg->cbb;
3784
3785         return ins;
3786 }
3787
3788 /*
3789  * Returns NULL and set the cfg exception on error.
3790  */
3791 static MonoInst*
3792 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3793 {
3794         MonoInst *iargs [2];
3795         void *alloc_ftn;
3796
3797         if (context_used) {
3798                 MonoInst *data;
3799                 int rgctx_info;
3800                 MonoInst *iargs [2];
3801
3802                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3803
3804                 if (cfg->opt & MONO_OPT_SHARED)
3805                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3806                 else
3807                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3808                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3809
3810                 if (cfg->opt & MONO_OPT_SHARED) {
3811                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3812                         iargs [1] = data;
3813                         alloc_ftn = mono_object_new;
3814                 } else {
3815                         iargs [0] = data;
3816                         alloc_ftn = mono_object_new_specific;
3817                 }
3818
3819                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3820                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3821
3822                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3823         }
3824
3825         if (cfg->opt & MONO_OPT_SHARED) {
3826                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3827                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3828
3829                 alloc_ftn = mono_object_new;
3830         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3831                 /* This happens often in argument checking code, eg. throw new FooException... */
3832                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3833                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3834                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3835         } else {
3836                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3837                 MonoMethod *managed_alloc = NULL;
3838                 gboolean pass_lw;
3839
3840                 if (!vtable) {
3841                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3842                         cfg->exception_ptr = klass;
3843                         return NULL;
3844                 }
3845
3846 #ifndef MONO_CROSS_COMPILE
3847                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3848 #endif
3849
3850                 if (managed_alloc) {
3851                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3852                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3853                 }
3854                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3855                 if (pass_lw) {
3856                         guint32 lw = vtable->klass->instance_size;
3857                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3858                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3859                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3860                 }
3861                 else {
3862                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3863                 }
3864         }
3865
3866         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3867 }
3868         
3869 /*
3870  * Returns NULL and set the cfg exception on error.
3871  */     
3872 static MonoInst*
3873 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3874 {
3875         MonoInst *alloc, *ins;
3876
3877         *out_cbb = cfg->cbb;
3878
3879         if (mono_class_is_nullable (klass)) {
3880                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3881
3882                 if (context_used) {
3883                         /* FIXME: What if the class is shared?  We might not
3884                            have to get the method address from the RGCTX. */
3885                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3886                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3887                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3888
3889                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3890                 } else {
3891                         gboolean pass_vtable, pass_mrgctx;
3892                         MonoInst *rgctx_arg = NULL;
3893
3894                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3895                         g_assert (!pass_mrgctx);
3896
3897                         if (pass_vtable) {
3898                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3899
3900                                 g_assert (vtable);
3901                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3902                         }
3903
3904                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3905                 }
3906         }
3907
3908         if (mini_is_gsharedvt_klass (cfg, klass)) {
3909                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3910                 MonoInst *res, *is_ref, *src_var, *addr;
3911                 int addr_reg, dreg;
3912
3913                 dreg = alloc_ireg (cfg);
3914
3915                 NEW_BBLOCK (cfg, is_ref_bb);
3916                 NEW_BBLOCK (cfg, is_nullable_bb);
3917                 NEW_BBLOCK (cfg, end_bb);
3918                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3919                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3920                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3921
3922                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3923                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3924
3925                 /* Non-ref case */
3926                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3927                 if (!alloc)
3928                         return NULL;
3929                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3930                 ins->opcode = OP_STOREV_MEMBASE;
3931
3932                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3933                 res->type = STACK_OBJ;
3934                 res->klass = klass;
3935                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3936                 
3937                 /* Ref case */
3938                 MONO_START_BB (cfg, is_ref_bb);
3939                 addr_reg = alloc_ireg (cfg);
3940
3941                 /* val is a vtype, so has to load the value manually */
3942                 src_var = get_vreg_to_inst (cfg, val->dreg);
3943                 if (!src_var)
3944                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3945                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3946                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3947                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3948
3949                 /* Nullable case */
3950                 MONO_START_BB (cfg, is_nullable_bb);
3951
3952                 {
3953                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3954                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3955                         MonoInst *box_call;
3956                         MonoMethodSignature *box_sig;
3957
3958                         /*
3959                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3960                          * construct that method at JIT time, so have to do things by hand.
3961                          */
3962                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3963                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3964                         box_sig->param_count = 1;
3965                         box_sig->params [0] = &klass->byval_arg;
3966                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3967                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3968                         res->type = STACK_OBJ;
3969                         res->klass = klass;
3970                 }
3971
3972                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3973
3974                 MONO_START_BB (cfg, end_bb);
3975
3976                 *out_cbb = cfg->cbb;
3977
3978                 return res;
3979         } else {
3980                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3981                 if (!alloc)
3982                         return NULL;
3983
3984                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3985                 return alloc;
3986         }
3987 }
3988
3989
3990 static gboolean
3991 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3992 {
3993         int i;
3994         MonoGenericContainer *container;
3995         MonoGenericInst *ginst;
3996
3997         if (klass->generic_class) {
3998                 container = klass->generic_class->container_class->generic_container;
3999                 ginst = klass->generic_class->context.class_inst;
4000         } else if (klass->generic_container && context_used) {
4001                 container = klass->generic_container;
4002                 ginst = container->context.class_inst;
4003         } else {
4004                 return FALSE;
4005         }
4006
4007         for (i = 0; i < container->type_argc; ++i) {
4008                 MonoType *type;
4009                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4010                         continue;
4011                 type = ginst->type_argv [i];
4012                 if (mini_type_is_reference (cfg, type))
4013                         return TRUE;
4014         }
4015         return FALSE;
4016 }
4017
4018 // FIXME: This doesn't work yet (class libs tests fail?)
4019 #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)
4020
4021 static MonoInst*
4022 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4023 {
4024         MonoMethod *mono_castclass;
4025         MonoInst *res;
4026
4027         mono_castclass = mono_marshal_get_castclass_with_cache ();
4028
4029         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4030         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4031         reset_cast_details (cfg);
4032
4033         return res;
4034 }
4035
4036 /*
4037  * Returns NULL and set the cfg exception on error.
4038  */
4039 static MonoInst*
4040 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4041 {
4042         MonoBasicBlock *is_null_bb;
4043         int obj_reg = src->dreg;
4044         int vtable_reg = alloc_preg (cfg);
4045         MonoInst *klass_inst = NULL;
4046
4047         if (context_used) {
4048                 MonoInst *args [3];
4049
4050                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4051                         MonoInst *cache_ins;
4052
4053                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4054
4055                         /* obj */
4056                         args [0] = src;
4057
4058                         /* klass - it's the second element of the cache entry*/
4059                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4060
4061                         /* cache */
4062                         args [2] = cache_ins;
4063
4064                         return emit_castclass_with_cache (cfg, klass, args, NULL);
4065                 }
4066
4067                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4068         }
4069
4070         NEW_BBLOCK (cfg, is_null_bb);
4071
4072         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4073         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4074
4075         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4076
4077         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4078                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4079                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4080         } else {
4081                 int klass_reg = alloc_preg (cfg);
4082
4083                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4084
4085                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4086                         /* the remoting code is broken, access the class for now */
4087                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4088                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4089                                 if (!vt) {
4090                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4091                                         cfg->exception_ptr = klass;
4092                                         return NULL;
4093                                 }
4094                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4095                         } else {
4096                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4097                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4098                         }
4099                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4100                 } else {
4101                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4102                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4103                 }
4104         }
4105
4106         MONO_START_BB (cfg, is_null_bb);
4107
4108         reset_cast_details (cfg);
4109
4110         return src;
4111 }
4112
4113 /*
4114  * Returns NULL and set the cfg exception on error.
4115  */
4116 static MonoInst*
4117 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4118 {
4119         MonoInst *ins;
4120         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4121         int obj_reg = src->dreg;
4122         int vtable_reg = alloc_preg (cfg);
4123         int res_reg = alloc_ireg_ref (cfg);
4124         MonoInst *klass_inst = NULL;
4125
4126         if (context_used) {
4127                 MonoInst *args [3];
4128
4129                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4130                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4131                         MonoInst *cache_ins;
4132
4133                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4134
4135                         /* obj */
4136                         args [0] = src;
4137
4138                         /* klass - it's the second element of the cache entry*/
4139                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4140
4141                         /* cache */
4142                         args [2] = cache_ins;
4143
4144                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4145                 }
4146
4147                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4148         }
4149
4150         NEW_BBLOCK (cfg, is_null_bb);
4151         NEW_BBLOCK (cfg, false_bb);
4152         NEW_BBLOCK (cfg, end_bb);
4153
4154         /* Do the assignment at the beginning, so the other assignment can be if converted */
4155         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4156         ins->type = STACK_OBJ;
4157         ins->klass = klass;
4158
4159         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4160         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4161
4162         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4163
4164         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4165                 g_assert (!context_used);
4166                 /* the is_null_bb target simply copies the input register to the output */
4167                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4168         } else {
4169                 int klass_reg = alloc_preg (cfg);
4170
4171                 if (klass->rank) {
4172                         int rank_reg = alloc_preg (cfg);
4173                         int eclass_reg = alloc_preg (cfg);
4174
4175                         g_assert (!context_used);
4176                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4177                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4178                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4179                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4180                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4181                         if (klass->cast_class == mono_defaults.object_class) {
4182                                 int parent_reg = alloc_preg (cfg);
4183                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4184                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4185                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4186                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4187                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4188                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4189                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4190                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4191                         } else if (klass->cast_class == mono_defaults.enum_class) {
4192                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4193                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4194                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4195                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4196                         } else {
4197                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4198                                         /* Check that the object is a vector too */
4199                                         int bounds_reg = alloc_preg (cfg);
4200                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4201                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4202                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4203                                 }
4204
4205                                 /* the is_null_bb target simply copies the input register to the output */
4206                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4207                         }
4208                 } else if (mono_class_is_nullable (klass)) {
4209                         g_assert (!context_used);
4210                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4211                         /* the is_null_bb target simply copies the input register to the output */
4212                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4213                 } else {
4214                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4215                                 g_assert (!context_used);
4216                                 /* the remoting code is broken, access the class for now */
4217                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4218                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4219                                         if (!vt) {
4220                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4221                                                 cfg->exception_ptr = klass;
4222                                                 return NULL;
4223                                         }
4224                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4225                                 } else {
4226                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4227                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4228                                 }
4229                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4230                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4231                         } else {
4232                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4233                                 /* the is_null_bb target simply copies the input register to the output */
4234                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4235                         }
4236                 }
4237         }
4238
4239         MONO_START_BB (cfg, false_bb);
4240
4241         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4242         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4243
4244         MONO_START_BB (cfg, is_null_bb);
4245
4246         MONO_START_BB (cfg, end_bb);
4247
4248         return ins;
4249 }
4250
4251 static MonoInst*
4252 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4253 {
4254         /* This opcode takes as input an object reference and a class, and returns:
4255         0) if the object is an instance of the class,
4256         1) if the object is not instance of the class,
4257         2) if the object is a proxy whose type cannot be determined */
4258
4259         MonoInst *ins;
4260 #ifndef DISABLE_REMOTING
4261         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4262 #else
4263         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4264 #endif
4265         int obj_reg = src->dreg;
4266         int dreg = alloc_ireg (cfg);
4267         int tmp_reg;
4268 #ifndef DISABLE_REMOTING
4269         int klass_reg = alloc_preg (cfg);
4270 #endif
4271
4272         NEW_BBLOCK (cfg, true_bb);
4273         NEW_BBLOCK (cfg, false_bb);
4274         NEW_BBLOCK (cfg, end_bb);
4275 #ifndef DISABLE_REMOTING
4276         NEW_BBLOCK (cfg, false2_bb);
4277         NEW_BBLOCK (cfg, no_proxy_bb);
4278 #endif
4279
4280         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4281         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4282
4283         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4284 #ifndef DISABLE_REMOTING
4285                 NEW_BBLOCK (cfg, interface_fail_bb);
4286 #endif
4287
4288                 tmp_reg = alloc_preg (cfg);
4289                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4290 #ifndef DISABLE_REMOTING
4291                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4292                 MONO_START_BB (cfg, interface_fail_bb);
4293                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4294                 
4295                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4296
4297                 tmp_reg = alloc_preg (cfg);
4298                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4299                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4300                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4301 #else
4302                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4303 #endif
4304         } else {
4305 #ifndef DISABLE_REMOTING
4306                 tmp_reg = alloc_preg (cfg);
4307                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4308                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4309
4310                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4311                 tmp_reg = alloc_preg (cfg);
4312                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4313                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4314
4315                 tmp_reg = alloc_preg (cfg);             
4316                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4317                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4318                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4319                 
4320                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4321                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4322
4323                 MONO_START_BB (cfg, no_proxy_bb);
4324
4325                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4326 #else
4327                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4328 #endif
4329         }
4330
4331         MONO_START_BB (cfg, false_bb);
4332
4333         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4334         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4335
4336 #ifndef DISABLE_REMOTING
4337         MONO_START_BB (cfg, false2_bb);
4338
4339         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4340         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4341 #endif
4342
4343         MONO_START_BB (cfg, true_bb);
4344
4345         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4346
4347         MONO_START_BB (cfg, end_bb);
4348
4349         /* FIXME: */
4350         MONO_INST_NEW (cfg, ins, OP_ICONST);
4351         ins->dreg = dreg;
4352         ins->type = STACK_I4;
4353
4354         return ins;
4355 }
4356
4357 static MonoInst*
4358 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4359 {
4360         /* This opcode takes as input an object reference and a class, and returns:
4361         0) if the object is an instance of the class,
4362         1) if the object is a proxy whose type cannot be determined
4363         an InvalidCastException exception is thrown otherwhise*/
4364         
4365         MonoInst *ins;
4366 #ifndef DISABLE_REMOTING
4367         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4368 #else
4369         MonoBasicBlock *ok_result_bb;
4370 #endif
4371         int obj_reg = src->dreg;
4372         int dreg = alloc_ireg (cfg);
4373         int tmp_reg = alloc_preg (cfg);
4374
4375 #ifndef DISABLE_REMOTING
4376         int klass_reg = alloc_preg (cfg);
4377         NEW_BBLOCK (cfg, end_bb);
4378 #endif
4379
4380         NEW_BBLOCK (cfg, ok_result_bb);
4381
4382         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4383         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4384
4385         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4386
4387         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4388 #ifndef DISABLE_REMOTING
4389                 NEW_BBLOCK (cfg, interface_fail_bb);
4390         
4391                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4392                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4393                 MONO_START_BB (cfg, interface_fail_bb);
4394                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4395
4396                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4397
4398                 tmp_reg = alloc_preg (cfg);             
4399                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4400                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4401                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4402                 
4403                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4404                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4405 #else
4406                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4407                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4408                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4409 #endif
4410         } else {
4411 #ifndef DISABLE_REMOTING
4412                 NEW_BBLOCK (cfg, no_proxy_bb);
4413
4414                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4415                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4416                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4417
4418                 tmp_reg = alloc_preg (cfg);
4419                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4420                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4421
4422                 tmp_reg = alloc_preg (cfg);
4423                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4424                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4425                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4426
4427                 NEW_BBLOCK (cfg, fail_1_bb);
4428                 
4429                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4430
4431                 MONO_START_BB (cfg, fail_1_bb);
4432
4433                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4434                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4435
4436                 MONO_START_BB (cfg, no_proxy_bb);
4437
4438                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4439 #else
4440                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4441 #endif
4442         }
4443
4444         MONO_START_BB (cfg, ok_result_bb);
4445
4446         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4447
4448 #ifndef DISABLE_REMOTING
4449         MONO_START_BB (cfg, end_bb);
4450 #endif
4451
4452         /* FIXME: */
4453         MONO_INST_NEW (cfg, ins, OP_ICONST);
4454         ins->dreg = dreg;
4455         ins->type = STACK_I4;
4456
4457         return ins;
4458 }
4459
4460 /*
4461  * Returns NULL and set the cfg exception on error.
4462  */
4463 static G_GNUC_UNUSED MonoInst*
4464 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4465 {
4466         MonoInst *ptr;
4467         int dreg;
4468         gpointer *trampoline;
4469         MonoInst *obj, *method_ins, *tramp_ins;
4470         MonoDomain *domain;
4471         guint8 **code_slot;
4472
4473         obj = handle_alloc (cfg, klass, FALSE, 0);
4474         if (!obj)
4475                 return NULL;
4476
4477         /* Inline the contents of mono_delegate_ctor */
4478
4479         /* Set target field */
4480         /* Optimize away setting of NULL target */
4481         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4482                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4483                 if (cfg->gen_write_barriers) {
4484                         dreg = alloc_preg (cfg);
4485                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4486                         emit_write_barrier (cfg, ptr, target);
4487                 }
4488         }
4489
4490         /* Set method field */
4491         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4492         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4493         if (cfg->gen_write_barriers) {
4494                 dreg = alloc_preg (cfg);
4495                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4496                 emit_write_barrier (cfg, ptr, method_ins);
4497         }
4498         /* 
4499          * To avoid looking up the compiled code belonging to the target method
4500          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4501          * store it, and we fill it after the method has been compiled.
4502          */
4503         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4504                 MonoInst *code_slot_ins;
4505
4506                 if (context_used) {
4507                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4508                 } else {
4509                         domain = mono_domain_get ();
4510                         mono_domain_lock (domain);
4511                         if (!domain_jit_info (domain)->method_code_hash)
4512                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4513                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4514                         if (!code_slot) {
4515                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4516                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4517                         }
4518                         mono_domain_unlock (domain);
4519
4520                         if (cfg->compile_aot)
4521                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4522                         else
4523                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4524                 }
4525                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4526         }
4527
4528         /* Set invoke_impl field */
4529         if (cfg->compile_aot) {
4530                 MonoClassMethodPair *del_tramp;
4531
4532                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoClassMethodPair));
4533                 del_tramp->klass = klass;
4534                 del_tramp->method = context_used ? NULL : method;
4535                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4536         } else {
4537                 trampoline = mono_create_delegate_trampoline_with_method (cfg->domain, klass, context_used ? NULL : method);
4538                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4539         }
4540         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4541
4542         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4543
4544         return obj;
4545 }
4546
4547 static MonoInst*
4548 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4549 {
4550         MonoJitICallInfo *info;
4551
4552         /* Need to register the icall so it gets an icall wrapper */
4553         info = mono_get_array_new_va_icall (rank);
4554
4555         cfg->flags |= MONO_CFG_HAS_VARARGS;
4556
4557         /* mono_array_new_va () needs a vararg calling convention */
4558         cfg->disable_llvm = TRUE;
4559
4560         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4561         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4562 }
4563
4564 static void
4565 mono_emit_load_got_addr (MonoCompile *cfg)
4566 {
4567         MonoInst *getaddr, *dummy_use;
4568
4569         if (!cfg->got_var || cfg->got_var_allocated)
4570                 return;
4571
4572         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4573         getaddr->cil_code = cfg->header->code;
4574         getaddr->dreg = cfg->got_var->dreg;
4575
4576         /* Add it to the start of the first bblock */
4577         if (cfg->bb_entry->code) {
4578                 getaddr->next = cfg->bb_entry->code;
4579                 cfg->bb_entry->code = getaddr;
4580         }
4581         else
4582                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4583
4584         cfg->got_var_allocated = TRUE;
4585
4586         /* 
4587          * Add a dummy use to keep the got_var alive, since real uses might
4588          * only be generated by the back ends.
4589          * Add it to end_bblock, so the variable's lifetime covers the whole
4590          * method.
4591          * It would be better to make the usage of the got var explicit in all
4592          * cases when the backend needs it (i.e. calls, throw etc.), so this
4593          * wouldn't be needed.
4594          */
4595         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4596         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4597 }
4598
4599 static int inline_limit;
4600 static gboolean inline_limit_inited;
4601
4602 static gboolean
4603 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4604 {
4605         MonoMethodHeaderSummary header;
4606         MonoVTable *vtable;
4607 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4608         MonoMethodSignature *sig = mono_method_signature (method);
4609         int i;
4610 #endif
4611
4612         if (cfg->generic_sharing_context)
4613                 return FALSE;
4614
4615         if (cfg->inline_depth > 10)
4616                 return FALSE;
4617
4618 #ifdef MONO_ARCH_HAVE_LMF_OPS
4619         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4620                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4621             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4622                 return TRUE;
4623 #endif
4624
4625
4626         if (!mono_method_get_header_summary (method, &header))
4627                 return FALSE;
4628
4629         /*runtime, icall and pinvoke are checked by summary call*/
4630         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4631             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4632             (mono_class_is_marshalbyref (method->klass)) ||
4633             header.has_clauses)
4634                 return FALSE;
4635
4636         /* also consider num_locals? */
4637         /* Do the size check early to avoid creating vtables */
4638         if (!inline_limit_inited) {
4639                 if (g_getenv ("MONO_INLINELIMIT"))
4640                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4641                 else
4642                         inline_limit = INLINE_LENGTH_LIMIT;
4643                 inline_limit_inited = TRUE;
4644         }
4645         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4646                 return FALSE;
4647
4648         /*
4649          * if we can initialize the class of the method right away, we do,
4650          * otherwise we don't allow inlining if the class needs initialization,
4651          * since it would mean inserting a call to mono_runtime_class_init()
4652          * inside the inlined code
4653          */
4654         if (!(cfg->opt & MONO_OPT_SHARED)) {
4655                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4656                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4657                         vtable = mono_class_vtable (cfg->domain, method->klass);
4658                         if (!vtable)
4659                                 return FALSE;
4660                         if (!cfg->compile_aot)
4661                                 mono_runtime_class_init (vtable);
4662                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4663                         if (cfg->run_cctors && method->klass->has_cctor) {
4664                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4665                                 if (!method->klass->runtime_info)
4666                                         /* No vtable created yet */
4667                                         return FALSE;
4668                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4669                                 if (!vtable)
4670                                         return FALSE;
4671                                 /* This makes so that inline cannot trigger */
4672                                 /* .cctors: too many apps depend on them */
4673                                 /* running with a specific order... */
4674                                 if (! vtable->initialized)
4675                                         return FALSE;
4676                                 mono_runtime_class_init (vtable);
4677                         }
4678                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4679                         if (!method->klass->runtime_info)
4680                                 /* No vtable created yet */
4681                                 return FALSE;
4682                         vtable = mono_class_vtable (cfg->domain, method->klass);
4683                         if (!vtable)
4684                                 return FALSE;
4685                         if (!vtable->initialized)
4686                                 return FALSE;
4687                 }
4688         } else {
4689                 /* 
4690                  * If we're compiling for shared code
4691                  * the cctor will need to be run at aot method load time, for example,
4692                  * or at the end of the compilation of the inlining method.
4693                  */
4694                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4695                         return FALSE;
4696         }
4697
4698         /*
4699          * CAS - do not inline methods with declarative security
4700          * Note: this has to be before any possible return TRUE;
4701          */
4702         if (mono_security_method_has_declsec (method))
4703                 return FALSE;
4704
4705 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4706         if (mono_arch_is_soft_float ()) {
4707                 /* FIXME: */
4708                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4709                         return FALSE;
4710                 for (i = 0; i < sig->param_count; ++i)
4711                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4712                                 return FALSE;
4713         }
4714 #endif
4715
4716         return TRUE;
4717 }
4718
4719 static gboolean
4720 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4721 {
4722         if (!cfg->compile_aot) {
4723                 g_assert (vtable);
4724                 if (vtable->initialized)
4725                         return FALSE;
4726         }
4727
4728         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4729                 if (cfg->method == method)
4730                         return FALSE;
4731         }
4732
4733         if (!mono_class_needs_cctor_run (klass, method))
4734                 return FALSE;
4735
4736         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4737                 /* The initialization is already done before the method is called */
4738                 return FALSE;
4739
4740         return TRUE;
4741 }
4742
4743 static MonoInst*
4744 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4745 {
4746         MonoInst *ins;
4747         guint32 size;
4748         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4749         int context_used;
4750
4751         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4752                 size = -1;
4753         } else {
4754                 mono_class_init (klass);
4755                 size = mono_class_array_element_size (klass);
4756         }
4757
4758         mult_reg = alloc_preg (cfg);
4759         array_reg = arr->dreg;
4760         index_reg = index->dreg;
4761
4762 #if SIZEOF_REGISTER == 8
4763         /* The array reg is 64 bits but the index reg is only 32 */
4764         if (COMPILE_LLVM (cfg)) {
4765                 /* Not needed */
4766                 index2_reg = index_reg;
4767         } else {
4768                 index2_reg = alloc_preg (cfg);
4769                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4770         }
4771 #else
4772         if (index->type == STACK_I8) {
4773                 index2_reg = alloc_preg (cfg);
4774                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4775         } else {
4776                 index2_reg = index_reg;
4777         }
4778 #endif
4779
4780         if (bcheck)
4781                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4782
4783 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4784         if (size == 1 || size == 2 || size == 4 || size == 8) {
4785                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4786
4787                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4788                 ins->klass = mono_class_get_element_class (klass);
4789                 ins->type = STACK_MP;
4790
4791                 return ins;
4792         }
4793 #endif          
4794
4795         add_reg = alloc_ireg_mp (cfg);
4796
4797         if (size == -1) {
4798                 MonoInst *rgctx_ins;
4799
4800                 /* gsharedvt */
4801                 g_assert (cfg->generic_sharing_context);
4802                 context_used = mini_class_check_context_used (cfg, klass);
4803                 g_assert (context_used);
4804                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4805                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4806         } else {
4807                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4808         }
4809         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4810         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4811         ins->klass = mono_class_get_element_class (klass);
4812         ins->type = STACK_MP;
4813         MONO_ADD_INS (cfg->cbb, ins);
4814
4815         return ins;
4816 }
4817
4818 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4819 static MonoInst*
4820 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4821 {
4822         int bounds_reg = alloc_preg (cfg);
4823         int add_reg = alloc_ireg_mp (cfg);
4824         int mult_reg = alloc_preg (cfg);
4825         int mult2_reg = alloc_preg (cfg);
4826         int low1_reg = alloc_preg (cfg);
4827         int low2_reg = alloc_preg (cfg);
4828         int high1_reg = alloc_preg (cfg);
4829         int high2_reg = alloc_preg (cfg);
4830         int realidx1_reg = alloc_preg (cfg);
4831         int realidx2_reg = alloc_preg (cfg);
4832         int sum_reg = alloc_preg (cfg);
4833         int index1, index2, tmpreg;
4834         MonoInst *ins;
4835         guint32 size;
4836
4837         mono_class_init (klass);
4838         size = mono_class_array_element_size (klass);
4839
4840         index1 = index_ins1->dreg;
4841         index2 = index_ins2->dreg;
4842
4843 #if SIZEOF_REGISTER == 8
4844         /* The array reg is 64 bits but the index reg is only 32 */
4845         if (COMPILE_LLVM (cfg)) {
4846                 /* Not needed */
4847         } else {
4848                 tmpreg = alloc_preg (cfg);
4849                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4850                 index1 = tmpreg;
4851                 tmpreg = alloc_preg (cfg);
4852                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4853                 index2 = tmpreg;
4854         }
4855 #else
4856         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4857         tmpreg = -1;
4858 #endif
4859
4860         /* range checking */
4861         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4862                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4863
4864         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4865                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4866         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4867         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4868                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4869         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4870         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4871
4872         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4873                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4874         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4875         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4876                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4877         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4878         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4879
4880         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4881         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4882         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4883         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4884         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4885
4886         ins->type = STACK_MP;
4887         ins->klass = klass;
4888         MONO_ADD_INS (cfg->cbb, ins);
4889
4890         return ins;
4891 }
4892 #endif
4893
4894 static MonoInst*
4895 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4896 {
4897         int rank;
4898         MonoInst *addr;
4899         MonoMethod *addr_method;
4900         int element_size;
4901
4902         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4903
4904         if (rank == 1)
4905                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4906
4907 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4908         /* emit_ldelema_2 depends on OP_LMUL */
4909         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4910                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4911         }
4912 #endif
4913
4914         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4915         addr_method = mono_marshal_get_array_address (rank, element_size);
4916         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4917
4918         return addr;
4919 }
4920
4921 static MonoBreakPolicy
4922 always_insert_breakpoint (MonoMethod *method)
4923 {
4924         return MONO_BREAK_POLICY_ALWAYS;
4925 }
4926
4927 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4928
4929 /**
4930  * mono_set_break_policy:
4931  * policy_callback: the new callback function
4932  *
4933  * Allow embedders to decide wherther to actually obey breakpoint instructions
4934  * (both break IL instructions and Debugger.Break () method calls), for example
4935  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4936  * untrusted or semi-trusted code.
4937  *
4938  * @policy_callback will be called every time a break point instruction needs to
4939  * be inserted with the method argument being the method that calls Debugger.Break()
4940  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4941  * if it wants the breakpoint to not be effective in the given method.
4942  * #MONO_BREAK_POLICY_ALWAYS is the default.
4943  */
4944 void
4945 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4946 {
4947         if (policy_callback)
4948                 break_policy_func = policy_callback;
4949         else
4950                 break_policy_func = always_insert_breakpoint;
4951 }
4952
4953 static gboolean
4954 should_insert_brekpoint (MonoMethod *method) {
4955         switch (break_policy_func (method)) {
4956         case MONO_BREAK_POLICY_ALWAYS:
4957                 return TRUE;
4958         case MONO_BREAK_POLICY_NEVER:
4959                 return FALSE;
4960         case MONO_BREAK_POLICY_ON_DBG:
4961                 g_warning ("mdb no longer supported");
4962                 return FALSE;
4963         default:
4964                 g_warning ("Incorrect value returned from break policy callback");
4965                 return FALSE;
4966         }
4967 }
4968
4969 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4970 static MonoInst*
4971 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4972 {
4973         MonoInst *addr, *store, *load;
4974         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4975
4976         /* the bounds check is already done by the callers */
4977         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4978         if (is_set) {
4979                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4980                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4981                 if (mini_type_is_reference (cfg, fsig->params [2]))
4982                         emit_write_barrier (cfg, addr, load);
4983         } else {
4984                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4985                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4986         }
4987         return store;
4988 }
4989
4990
4991 static gboolean
4992 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4993 {
4994         return mini_type_is_reference (cfg, &klass->byval_arg);
4995 }
4996
4997 static MonoInst*
4998 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4999 {
5000         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5001                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5002                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5003                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5004                 MonoInst *iargs [3];
5005
5006                 if (!helper->slot)
5007                         mono_class_setup_vtable (obj_array);
5008                 g_assert (helper->slot);
5009
5010                 if (sp [0]->type != STACK_OBJ)
5011                         return NULL;
5012                 if (sp [2]->type != STACK_OBJ)
5013                         return NULL;
5014
5015                 iargs [2] = sp [2];
5016                 iargs [1] = sp [1];
5017                 iargs [0] = sp [0];
5018
5019                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5020         } else {
5021                 MonoInst *ins;
5022
5023                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5024                         MonoInst *addr;
5025
5026                         // FIXME-VT: OP_ICONST optimization
5027                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5028                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5029                         ins->opcode = OP_STOREV_MEMBASE;
5030                 } else if (sp [1]->opcode == OP_ICONST) {
5031                         int array_reg = sp [0]->dreg;
5032                         int index_reg = sp [1]->dreg;
5033                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
5034
5035                         if (safety_checks)
5036                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5037                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5038                 } else {
5039                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5040                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5041                         if (generic_class_is_reference_type (cfg, klass))
5042                                 emit_write_barrier (cfg, addr, sp [2]);
5043                 }
5044                 return ins;
5045         }
5046 }
5047
5048 static MonoInst*
5049 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5050 {
5051         MonoClass *eklass;
5052         
5053         if (is_set)
5054                 eklass = mono_class_from_mono_type (fsig->params [2]);
5055         else
5056                 eklass = mono_class_from_mono_type (fsig->ret);
5057
5058         if (is_set) {
5059                 return emit_array_store (cfg, eklass, args, FALSE);
5060         } else {
5061                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5062                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5063                 return ins;
5064         }
5065 }
5066
5067 static gboolean
5068 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5069 {
5070         uint32_t align;
5071
5072         //Only allow for valuetypes
5073         if (!param_klass->valuetype || !return_klass->valuetype)
5074                 return FALSE;
5075
5076         //That are blitable
5077         if (param_klass->has_references || return_klass->has_references)
5078                 return FALSE;
5079
5080         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5081         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5082                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5083                 return FALSE;
5084
5085         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5086                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5087                 return FALSE;
5088
5089         //And have the same size
5090         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5091                 return FALSE;
5092         return TRUE;
5093 }
5094
5095 static MonoInst*
5096 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5097 {
5098         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5099         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5100
5101         //Valuetypes that are semantically equivalent
5102         if (is_unsafe_mov_compatible (param_klass, return_klass))
5103                 return args [0];
5104
5105         //Arrays of valuetypes that are semantically equivalent
5106         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5107                 return args [0];
5108
5109         return NULL;
5110 }
5111
5112 static MonoInst*
5113 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5114 {
5115 #ifdef MONO_ARCH_SIMD_INTRINSICS
5116         MonoInst *ins = NULL;
5117
5118         if (cfg->opt & MONO_OPT_SIMD) {
5119                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5120                 if (ins)
5121                         return ins;
5122         }
5123 #endif
5124
5125         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5126 }
5127
5128 static MonoInst*
5129 emit_memory_barrier (MonoCompile *cfg, int kind)
5130 {
5131         MonoInst *ins = NULL;
5132         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5133         MONO_ADD_INS (cfg->cbb, ins);
5134         ins->backend.memory_barrier_kind = kind;
5135
5136         return ins;
5137 }
5138
5139 static MonoInst*
5140 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5141 {
5142         MonoInst *ins = NULL;
5143         int opcode = 0;
5144
5145         /* The LLVM backend supports these intrinsics */
5146         if (cmethod->klass == mono_defaults.math_class) {
5147                 if (strcmp (cmethod->name, "Sin") == 0) {
5148                         opcode = OP_SIN;
5149                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5150                         opcode = OP_COS;
5151                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5152                         opcode = OP_SQRT;
5153                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5154                         opcode = OP_ABS;
5155                 }
5156
5157                 if (opcode) {
5158                         MONO_INST_NEW (cfg, ins, opcode);
5159                         ins->type = STACK_R8;
5160                         ins->dreg = mono_alloc_freg (cfg);
5161                         ins->sreg1 = args [0]->dreg;
5162                         MONO_ADD_INS (cfg->cbb, ins);
5163                 }
5164
5165                 opcode = 0;
5166                 if (cfg->opt & MONO_OPT_CMOV) {
5167                         if (strcmp (cmethod->name, "Min") == 0) {
5168                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5169                                         opcode = OP_IMIN;
5170                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5171                                         opcode = OP_IMIN_UN;
5172                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5173                                         opcode = OP_LMIN;
5174                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5175                                         opcode = OP_LMIN_UN;
5176                         } else if (strcmp (cmethod->name, "Max") == 0) {
5177                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5178                                         opcode = OP_IMAX;
5179                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5180                                         opcode = OP_IMAX_UN;
5181                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5182                                         opcode = OP_LMAX;
5183                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5184                                         opcode = OP_LMAX_UN;
5185                         }
5186                 }
5187
5188                 if (opcode) {
5189                         MONO_INST_NEW (cfg, ins, opcode);
5190                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5191                         ins->dreg = mono_alloc_ireg (cfg);
5192                         ins->sreg1 = args [0]->dreg;
5193                         ins->sreg2 = args [1]->dreg;
5194                         MONO_ADD_INS (cfg->cbb, ins);
5195                 }
5196         }
5197
5198         return ins;
5199 }
5200
5201 static MonoInst*
5202 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5203 {
5204         if (cmethod->klass == mono_defaults.array_class) {
5205                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5206                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5207                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5208                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5209                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5210                         return emit_array_unsafe_mov (cfg, fsig, args);
5211         }
5212
5213         return NULL;
5214 }
5215
5216 static MonoInst*
5217 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5218 {
5219         MonoInst *ins = NULL;
5220         
5221         static MonoClass *runtime_helpers_class = NULL;
5222         if (! runtime_helpers_class)
5223                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5224                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5225
5226         if (cmethod->klass == mono_defaults.string_class) {
5227                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5228                         int dreg = alloc_ireg (cfg);
5229                         int index_reg = alloc_preg (cfg);
5230                         int mult_reg = alloc_preg (cfg);
5231                         int add_reg = alloc_preg (cfg);
5232
5233 #if SIZEOF_REGISTER == 8
5234                         /* The array reg is 64 bits but the index reg is only 32 */
5235                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5236 #else
5237                         index_reg = args [1]->dreg;
5238 #endif  
5239                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5240
5241 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5242                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5243                         add_reg = ins->dreg;
5244                         /* Avoid a warning */
5245                         mult_reg = 0;
5246                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5247                                                                    add_reg, 0);
5248 #else
5249                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5250                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5251                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5252                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5253 #endif
5254                         type_from_op (ins, NULL, NULL);
5255                         return ins;
5256                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5257                         int dreg = alloc_ireg (cfg);
5258                         /* Decompose later to allow more optimizations */
5259                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5260                         ins->type = STACK_I4;
5261                         ins->flags |= MONO_INST_FAULT;
5262                         cfg->cbb->has_array_access = TRUE;
5263                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5264
5265                         return ins;
5266                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5267                         int mult_reg = alloc_preg (cfg);
5268                         int add_reg = alloc_preg (cfg);
5269
5270                         /* The corlib functions check for oob already. */
5271                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5272                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5273                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5274                         return cfg->cbb->last_ins;
5275                 } else 
5276                         return NULL;
5277         } else if (cmethod->klass == mono_defaults.object_class) {
5278
5279                 if (strcmp (cmethod->name, "GetType") == 0) {
5280                         int dreg = alloc_ireg_ref (cfg);
5281                         int vt_reg = alloc_preg (cfg);
5282                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5283                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5284                         type_from_op (ins, NULL, NULL);
5285
5286                         return ins;
5287 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5288                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5289                         int dreg = alloc_ireg (cfg);
5290                         int t1 = alloc_ireg (cfg);
5291         
5292                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5293                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5294                         ins->type = STACK_I4;
5295
5296                         return ins;
5297 #endif
5298                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5299                         MONO_INST_NEW (cfg, ins, OP_NOP);
5300                         MONO_ADD_INS (cfg->cbb, ins);
5301                         return ins;
5302                 } else
5303                         return NULL;
5304         } else if (cmethod->klass == mono_defaults.array_class) {
5305                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5306                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5307
5308 #ifndef MONO_BIG_ARRAYS
5309                 /*
5310                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5311                  * Array methods.
5312                  */
5313                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5314                         int dreg = alloc_ireg (cfg);
5315                         int bounds_reg = alloc_ireg_mp (cfg);
5316                         MonoBasicBlock *end_bb, *szarray_bb;
5317                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5318
5319                         NEW_BBLOCK (cfg, end_bb);
5320                         NEW_BBLOCK (cfg, szarray_bb);
5321
5322                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5323                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5324                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5325                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5326                         /* Non-szarray case */
5327                         if (get_length)
5328                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5329                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5330                         else
5331                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5332                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5333                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5334                         MONO_START_BB (cfg, szarray_bb);
5335                         /* Szarray case */
5336                         if (get_length)
5337                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5338                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5339                         else
5340                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5341                         MONO_START_BB (cfg, end_bb);
5342
5343                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5344                         ins->type = STACK_I4;
5345                         
5346                         return ins;
5347                 }
5348 #endif
5349
5350                 if (cmethod->name [0] != 'g')
5351                         return NULL;
5352
5353                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5354                         int dreg = alloc_ireg (cfg);
5355                         int vtable_reg = alloc_preg (cfg);
5356                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5357                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5358                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5359                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5360                         type_from_op (ins, NULL, NULL);
5361
5362                         return ins;
5363                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5364                         int dreg = alloc_ireg (cfg);
5365
5366                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5367                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5368                         type_from_op (ins, NULL, NULL);
5369
5370                         return ins;
5371                 } else
5372                         return NULL;
5373         } else if (cmethod->klass == runtime_helpers_class) {
5374
5375                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5376                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5377                         return ins;
5378                 } else
5379                         return NULL;
5380         } else if (cmethod->klass == mono_defaults.thread_class) {
5381                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5382                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5383                         MONO_ADD_INS (cfg->cbb, ins);
5384                         return ins;
5385                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5386                         return emit_memory_barrier (cfg, FullBarrier);
5387                 }
5388         } else if (cmethod->klass == mono_defaults.monitor_class) {
5389
5390                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5391 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5392                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5393                         MonoMethod *fast_method = NULL;
5394
5395                         /* Avoid infinite recursion */
5396                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5397                                 return NULL;
5398                                 
5399                         fast_method = mono_monitor_get_fast_path (cmethod);
5400                         if (!fast_method)
5401                                 return NULL;
5402
5403                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5404                 }
5405 #endif
5406
5407 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5408                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5409                         MonoCallInst *call;
5410
5411                         if (COMPILE_LLVM (cfg)) {
5412                                 /* 
5413                                  * Pass the argument normally, the LLVM backend will handle the
5414                                  * calling convention problems.
5415                                  */
5416                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5417                         } else {
5418                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5419                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5420                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5421                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5422                         }
5423
5424                         return (MonoInst*)call;
5425                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5426                         MonoCallInst *call;
5427
5428                         if (COMPILE_LLVM (cfg)) {
5429                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5430                         } else {
5431                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5432                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5433                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5434                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5435                         }
5436
5437                         return (MonoInst*)call;
5438                 }
5439 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5440                 {
5441                 MonoMethod *fast_method = NULL;
5442
5443                 /* Avoid infinite recursion */
5444                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5445                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5446                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5447                         return NULL;
5448
5449                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5450                                 strcmp (cmethod->name, "Exit") == 0)
5451                         fast_method = mono_monitor_get_fast_path (cmethod);
5452                 if (!fast_method)
5453                         return NULL;
5454
5455                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5456                 }
5457 #endif
5458         } else if (cmethod->klass->image == mono_defaults.corlib &&
5459                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5460                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5461                 ins = NULL;
5462
5463 #if SIZEOF_REGISTER == 8
5464                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5465                         /* 64 bit reads are already atomic */
5466                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5467                         ins->dreg = mono_alloc_preg (cfg);
5468                         ins->inst_basereg = args [0]->dreg;
5469                         ins->inst_offset = 0;
5470                         MONO_ADD_INS (cfg->cbb, ins);
5471                 }
5472 #endif
5473
5474 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5475                 if (strcmp (cmethod->name, "Increment") == 0) {
5476                         MonoInst *ins_iconst;
5477                         guint32 opcode = 0;
5478
5479                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5480                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5481                                 cfg->has_atomic_add_new_i4 = TRUE;
5482                         }
5483 #if SIZEOF_REGISTER == 8
5484                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5485                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5486 #endif
5487                         if (opcode) {
5488                                 if (!mono_arch_opcode_supported (opcode))
5489                                         return NULL;
5490                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5491                                 ins_iconst->inst_c0 = 1;
5492                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5493                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5494
5495                                 MONO_INST_NEW (cfg, ins, opcode);
5496                                 ins->dreg = mono_alloc_ireg (cfg);
5497                                 ins->inst_basereg = args [0]->dreg;
5498                                 ins->inst_offset = 0;
5499                                 ins->sreg2 = ins_iconst->dreg;
5500                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5501                                 MONO_ADD_INS (cfg->cbb, ins);
5502                         }
5503                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5504                         MonoInst *ins_iconst;
5505                         guint32 opcode = 0;
5506
5507                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5508                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5509                                 cfg->has_atomic_add_new_i4 = TRUE;
5510                         }
5511 #if SIZEOF_REGISTER == 8
5512                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5513                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5514 #endif
5515                         if (opcode) {
5516                                 if (!mono_arch_opcode_supported (opcode))
5517                                         return NULL;
5518                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5519                                 ins_iconst->inst_c0 = -1;
5520                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5521                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5522
5523                                 MONO_INST_NEW (cfg, ins, opcode);
5524                                 ins->dreg = mono_alloc_ireg (cfg);
5525                                 ins->inst_basereg = args [0]->dreg;
5526                                 ins->inst_offset = 0;
5527                                 ins->sreg2 = ins_iconst->dreg;
5528                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5529                                 MONO_ADD_INS (cfg->cbb, ins);
5530                         }
5531                 } else if (strcmp (cmethod->name, "Add") == 0) {
5532                         guint32 opcode = 0;
5533
5534                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5535                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5536                                 cfg->has_atomic_add_new_i4 = TRUE;
5537                         }
5538 #if SIZEOF_REGISTER == 8
5539                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5540                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5541 #endif
5542                         if (opcode) {
5543                                 if (!mono_arch_opcode_supported (opcode))
5544                                         return NULL;
5545                                 MONO_INST_NEW (cfg, ins, opcode);
5546                                 ins->dreg = mono_alloc_ireg (cfg);
5547                                 ins->inst_basereg = args [0]->dreg;
5548                                 ins->inst_offset = 0;
5549                                 ins->sreg2 = args [1]->dreg;
5550                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5551                                 MONO_ADD_INS (cfg->cbb, ins);
5552                         }
5553                 }
5554 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5555
5556 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5557                 if (strcmp (cmethod->name, "Exchange") == 0) {
5558                         guint32 opcode;
5559                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5560
5561                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5562                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5563                                 cfg->has_atomic_exchange_i4 = TRUE;
5564                         }
5565 #if SIZEOF_REGISTER == 8
5566                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5567                                         (fsig->params [0]->type == MONO_TYPE_I))
5568                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5569 #else
5570                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5571                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5572                                 cfg->has_atomic_exchange_i4 = TRUE;
5573                         }
5574 #endif
5575                         else
5576                                 return NULL;
5577
5578                         if (!mono_arch_opcode_supported (opcode))
5579                                 return NULL;
5580
5581                         MONO_INST_NEW (cfg, ins, opcode);
5582                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5583                         ins->inst_basereg = args [0]->dreg;
5584                         ins->inst_offset = 0;
5585                         ins->sreg2 = args [1]->dreg;
5586                         MONO_ADD_INS (cfg->cbb, ins);
5587
5588                         switch (fsig->params [0]->type) {
5589                         case MONO_TYPE_I4:
5590                                 ins->type = STACK_I4;
5591                                 break;
5592                         case MONO_TYPE_I8:
5593                         case MONO_TYPE_I:
5594                                 ins->type = STACK_I8;
5595                                 break;
5596                         case MONO_TYPE_OBJECT:
5597                                 ins->type = STACK_OBJ;
5598                                 break;
5599                         default:
5600                                 g_assert_not_reached ();
5601                         }
5602
5603                         if (cfg->gen_write_barriers && is_ref)
5604                                 emit_write_barrier (cfg, args [0], args [1]);
5605                 }
5606 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5607  
5608 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5609                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5610                         int size = 0;
5611                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5612                         if (fsig->params [1]->type == MONO_TYPE_I4)
5613                                 size = 4;
5614                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5615                                 size = sizeof (gpointer);
5616                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5617                                 size = 8;
5618                         if (size == 4) {
5619                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5620                                         return NULL;
5621                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5622                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5623                                 ins->sreg1 = args [0]->dreg;
5624                                 ins->sreg2 = args [1]->dreg;
5625                                 ins->sreg3 = args [2]->dreg;
5626                                 ins->type = STACK_I4;
5627                                 MONO_ADD_INS (cfg->cbb, ins);
5628                                 cfg->has_atomic_cas_i4 = TRUE;
5629                         } else if (size == 8) {
5630                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5631                                         return NULL;
5632                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5633                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5634                                 ins->sreg1 = args [0]->dreg;
5635                                 ins->sreg2 = args [1]->dreg;
5636                                 ins->sreg3 = args [2]->dreg;
5637                                 ins->type = STACK_I8;
5638                                 MONO_ADD_INS (cfg->cbb, ins);
5639                         } else {
5640                                 /* g_assert_not_reached (); */
5641                         }
5642                         if (cfg->gen_write_barriers && is_ref)
5643                                 emit_write_barrier (cfg, args [0], args [1]);
5644                 }
5645 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5646
5647                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5648                         ins = emit_memory_barrier (cfg, FullBarrier);
5649
5650                 if (ins)
5651                         return ins;
5652         } else if (cmethod->klass->image == mono_defaults.corlib) {
5653                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5654                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5655                         if (should_insert_brekpoint (cfg->method)) {
5656                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5657                         } else {
5658                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5659                                 MONO_ADD_INS (cfg->cbb, ins);
5660                         }
5661                         return ins;
5662                 }
5663                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5664                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5665 #ifdef TARGET_WIN32
5666                         EMIT_NEW_ICONST (cfg, ins, 1);
5667 #else
5668                         EMIT_NEW_ICONST (cfg, ins, 0);
5669 #endif
5670                         return ins;
5671                 }
5672         } else if (cmethod->klass == mono_defaults.math_class) {
5673                 /* 
5674                  * There is general branches code for Min/Max, but it does not work for 
5675                  * all inputs:
5676                  * http://everything2.com/?node_id=1051618
5677                  */
5678         } 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)) {
5679 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5680                 MonoInst *pi;
5681                 MonoJumpInfoToken *ji;
5682                 MonoString *s;
5683
5684                 cfg->disable_llvm = TRUE;
5685
5686                 if (args [0]->opcode == OP_GOT_ENTRY) {
5687                         pi = args [0]->inst_p1;
5688                         g_assert (pi->opcode == OP_PATCH_INFO);
5689                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5690                         ji = pi->inst_p0;
5691                 } else {
5692                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5693                         ji = args [0]->inst_p0;
5694                 }
5695
5696                 NULLIFY_INS (args [0]);
5697
5698                 // FIXME: Ugly
5699                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5700                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5701                 ins->dreg = mono_alloc_ireg (cfg);
5702                 // FIXME: Leaks
5703                 ins->inst_p0 = mono_string_to_utf8 (s);
5704                 MONO_ADD_INS (cfg->cbb, ins);
5705                 return ins;
5706 #endif
5707         }
5708
5709 #ifdef MONO_ARCH_SIMD_INTRINSICS
5710         if (cfg->opt & MONO_OPT_SIMD) {
5711                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5712                 if (ins)
5713                         return ins;
5714         }
5715 #endif
5716
5717         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5718         if (ins)
5719                 return ins;
5720
5721         if (COMPILE_LLVM (cfg)) {
5722                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5723                 if (ins)
5724                         return ins;
5725         }
5726
5727         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5728 }
5729
5730 /*
5731  * This entry point could be used later for arbitrary method
5732  * redirection.
5733  */
5734 inline static MonoInst*
5735 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5736                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5737 {
5738         if (method->klass == mono_defaults.string_class) {
5739                 /* managed string allocation support */
5740                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5741                         MonoInst *iargs [2];
5742                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5743                         MonoMethod *managed_alloc = NULL;
5744
5745                         g_assert (vtable); /*Should not fail since it System.String*/
5746 #ifndef MONO_CROSS_COMPILE
5747                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5748 #endif
5749                         if (!managed_alloc)
5750                                 return NULL;
5751                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5752                         iargs [1] = args [0];
5753                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5754                 }
5755         }
5756         return NULL;
5757 }
5758
5759 static void
5760 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5761 {
5762         MonoInst *store, *temp;
5763         int i;
5764
5765         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5766                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5767
5768                 /*
5769                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5770                  * would be different than the MonoInst's used to represent arguments, and
5771                  * the ldelema implementation can't deal with that.
5772                  * Solution: When ldelema is used on an inline argument, create a var for 
5773                  * it, emit ldelema on that var, and emit the saving code below in
5774                  * inline_method () if needed.
5775                  */
5776                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5777                 cfg->args [i] = temp;
5778                 /* This uses cfg->args [i] which is set by the preceeding line */
5779                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5780                 store->cil_code = sp [0]->cil_code;
5781                 sp++;
5782         }
5783 }
5784
5785 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5786 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5787
5788 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5789 static gboolean
5790 check_inline_called_method_name_limit (MonoMethod *called_method)
5791 {
5792         int strncmp_result;
5793         static const char *limit = NULL;
5794         
5795         if (limit == NULL) {
5796                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5797
5798                 if (limit_string != NULL)
5799                         limit = limit_string;
5800                 else
5801                         limit = "";
5802         }
5803
5804         if (limit [0] != '\0') {
5805                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5806
5807                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5808                 g_free (called_method_name);
5809         
5810                 //return (strncmp_result <= 0);
5811                 return (strncmp_result == 0);
5812         } else {
5813                 return TRUE;
5814         }
5815 }
5816 #endif
5817
5818 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5819 static gboolean
5820 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5821 {
5822         int strncmp_result;
5823         static const char *limit = NULL;
5824         
5825         if (limit == NULL) {
5826                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5827                 if (limit_string != NULL) {
5828                         limit = limit_string;
5829                 } else {
5830                         limit = "";
5831                 }
5832         }
5833
5834         if (limit [0] != '\0') {
5835                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5836
5837                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5838                 g_free (caller_method_name);
5839         
5840                 //return (strncmp_result <= 0);
5841                 return (strncmp_result == 0);
5842         } else {
5843                 return TRUE;
5844         }
5845 }
5846 #endif
5847
5848 static void
5849 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5850 {
5851         static double r8_0 = 0.0;
5852         MonoInst *ins;
5853         int t;
5854
5855         rtype = mini_replace_type (rtype);
5856         t = rtype->type;
5857
5858         if (rtype->byref) {
5859                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5860         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5861                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5862         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5863                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5864         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5865                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5866                 ins->type = STACK_R8;
5867                 ins->inst_p0 = (void*)&r8_0;
5868                 ins->dreg = dreg;
5869                 MONO_ADD_INS (cfg->cbb, ins);
5870         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5871                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5872                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5873         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5874                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5875         } else {
5876                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5877         }
5878 }
5879
5880 static void
5881 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5882 {
5883         int t;
5884
5885         rtype = mini_replace_type (rtype);
5886         t = rtype->type;
5887
5888         if (rtype->byref) {
5889                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
5890         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5891                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
5892         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5893                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
5894         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5895                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
5896         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5897                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5898                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5899         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5900                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
5901         } else {
5902                 emit_init_rvar (cfg, dreg, rtype);
5903         }
5904 }
5905
5906 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
5907 static void
5908 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
5909 {
5910         MonoInst *var = cfg->locals [local];
5911         if (COMPILE_SOFT_FLOAT (cfg)) {
5912                 MonoInst *store;
5913                 int reg = alloc_dreg (cfg, var->type);
5914                 emit_init_rvar (cfg, reg, type);
5915                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5916         } else {
5917                 if (init)
5918                         emit_init_rvar (cfg, var->dreg, type);
5919                 else
5920                         emit_dummy_init_rvar (cfg, var->dreg, type);
5921         }
5922 }
5923
5924 static int
5925 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5926                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5927 {
5928         MonoInst *ins, *rvar = NULL;
5929         MonoMethodHeader *cheader;
5930         MonoBasicBlock *ebblock, *sbblock;
5931         int i, costs;
5932         MonoMethod *prev_inlined_method;
5933         MonoInst **prev_locals, **prev_args;
5934         MonoType **prev_arg_types;
5935         guint prev_real_offset;
5936         GHashTable *prev_cbb_hash;
5937         MonoBasicBlock **prev_cil_offset_to_bb;
5938         MonoBasicBlock *prev_cbb;
5939         unsigned char* prev_cil_start;
5940         guint32 prev_cil_offset_to_bb_len;
5941         MonoMethod *prev_current_method;
5942         MonoGenericContext *prev_generic_context;
5943         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5944
5945         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5946
5947 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5948         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5949                 return 0;
5950 #endif
5951 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5952         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5953                 return 0;
5954 #endif
5955
5956         if (cfg->verbose_level > 2)
5957                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5958
5959         if (!cmethod->inline_info) {
5960                 cfg->stat_inlineable_methods++;
5961                 cmethod->inline_info = 1;
5962         }
5963
5964         /* allocate local variables */
5965         cheader = mono_method_get_header (cmethod);
5966
5967         if (cheader == NULL || mono_loader_get_last_error ()) {
5968                 MonoLoaderError *error = mono_loader_get_last_error ();
5969
5970                 if (cheader)
5971                         mono_metadata_free_mh (cheader);
5972                 if (inline_always && error)
5973                         mono_cfg_set_exception (cfg, error->exception_type);
5974
5975                 mono_loader_clear_error ();
5976                 return 0;
5977         }
5978
5979         /*Must verify before creating locals as it can cause the JIT to assert.*/
5980         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5981                 mono_metadata_free_mh (cheader);
5982                 return 0;
5983         }
5984
5985         /* allocate space to store the return value */
5986         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5987                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5988         }
5989
5990         prev_locals = cfg->locals;
5991         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5992         for (i = 0; i < cheader->num_locals; ++i)
5993                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5994
5995         /* allocate start and end blocks */
5996         /* This is needed so if the inline is aborted, we can clean up */
5997         NEW_BBLOCK (cfg, sbblock);
5998         sbblock->real_offset = real_offset;
5999
6000         NEW_BBLOCK (cfg, ebblock);
6001         ebblock->block_num = cfg->num_bblocks++;
6002         ebblock->real_offset = real_offset;
6003
6004         prev_args = cfg->args;
6005         prev_arg_types = cfg->arg_types;
6006         prev_inlined_method = cfg->inlined_method;
6007         cfg->inlined_method = cmethod;
6008         cfg->ret_var_set = FALSE;
6009         cfg->inline_depth ++;
6010         prev_real_offset = cfg->real_offset;
6011         prev_cbb_hash = cfg->cbb_hash;
6012         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6013         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6014         prev_cil_start = cfg->cil_start;
6015         prev_cbb = cfg->cbb;
6016         prev_current_method = cfg->current_method;
6017         prev_generic_context = cfg->generic_context;
6018         prev_ret_var_set = cfg->ret_var_set;
6019
6020         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6021                 virtual = TRUE;
6022
6023         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
6024
6025         ret_var_set = cfg->ret_var_set;
6026
6027         cfg->inlined_method = prev_inlined_method;
6028         cfg->real_offset = prev_real_offset;
6029         cfg->cbb_hash = prev_cbb_hash;
6030         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6031         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6032         cfg->cil_start = prev_cil_start;
6033         cfg->locals = prev_locals;
6034         cfg->args = prev_args;
6035         cfg->arg_types = prev_arg_types;
6036         cfg->current_method = prev_current_method;
6037         cfg->generic_context = prev_generic_context;
6038         cfg->ret_var_set = prev_ret_var_set;
6039         cfg->inline_depth --;
6040
6041         if ((costs >= 0 && costs < 60) || inline_always) {
6042                 if (cfg->verbose_level > 2)
6043                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6044                 
6045                 cfg->stat_inlined_methods++;
6046
6047                 /* always add some code to avoid block split failures */
6048                 MONO_INST_NEW (cfg, ins, OP_NOP);
6049                 MONO_ADD_INS (prev_cbb, ins);
6050
6051                 prev_cbb->next_bb = sbblock;
6052                 link_bblock (cfg, prev_cbb, sbblock);
6053
6054                 /* 
6055                  * Get rid of the begin and end bblocks if possible to aid local
6056                  * optimizations.
6057                  */
6058                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6059
6060                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6061                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6062
6063                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6064                         MonoBasicBlock *prev = ebblock->in_bb [0];
6065                         mono_merge_basic_blocks (cfg, prev, ebblock);
6066                         cfg->cbb = prev;
6067                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6068                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6069                                 cfg->cbb = prev_cbb;
6070                         }
6071                 } else {
6072                         /* 
6073                          * Its possible that the rvar is set in some prev bblock, but not in others.
6074                          * (#1835).
6075                          */
6076                         if (rvar) {
6077                                 MonoBasicBlock *bb;
6078
6079                                 for (i = 0; i < ebblock->in_count; ++i) {
6080                                         bb = ebblock->in_bb [i];
6081
6082                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6083                                                 cfg->cbb = bb;
6084
6085                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6086                                         }
6087                                 }
6088                         }
6089
6090                         cfg->cbb = ebblock;
6091                 }
6092
6093                 if (rvar) {
6094                         /*
6095                          * If the inlined method contains only a throw, then the ret var is not 
6096                          * set, so set it to a dummy value.
6097                          */
6098                         if (!ret_var_set)
6099                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6100
6101                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6102                         *sp++ = ins;
6103                 }
6104                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6105                 return costs + 1;
6106         } else {
6107                 if (cfg->verbose_level > 2)
6108                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6109                 cfg->exception_type = MONO_EXCEPTION_NONE;
6110                 mono_loader_clear_error ();
6111
6112                 /* This gets rid of the newly added bblocks */
6113                 cfg->cbb = prev_cbb;
6114         }
6115         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6116         return 0;
6117 }
6118
6119 /*
6120  * Some of these comments may well be out-of-date.
6121  * Design decisions: we do a single pass over the IL code (and we do bblock 
6122  * splitting/merging in the few cases when it's required: a back jump to an IL
6123  * address that was not already seen as bblock starting point).
6124  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6125  * Complex operations are decomposed in simpler ones right away. We need to let the 
6126  * arch-specific code peek and poke inside this process somehow (except when the 
6127  * optimizations can take advantage of the full semantic info of coarse opcodes).
6128  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6129  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6130  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6131  * opcode with value bigger than OP_LAST.
6132  * At this point the IR can be handed over to an interpreter, a dumb code generator
6133  * or to the optimizing code generator that will translate it to SSA form.
6134  *
6135  * Profiling directed optimizations.
6136  * We may compile by default with few or no optimizations and instrument the code
6137  * or the user may indicate what methods to optimize the most either in a config file
6138  * or through repeated runs where the compiler applies offline the optimizations to 
6139  * each method and then decides if it was worth it.
6140  */
6141
6142 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6143 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6144 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6145 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6146 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6147 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6148 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6149 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
6150
6151 /* offset from br.s -> br like opcodes */
6152 #define BIG_BRANCH_OFFSET 13
6153
6154 static gboolean
6155 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6156 {
6157         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6158
6159         return b == NULL || b == bb;
6160 }
6161
6162 static int
6163 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6164 {
6165         unsigned char *ip = start;
6166         unsigned char *target;
6167         int i;
6168         guint cli_addr;
6169         MonoBasicBlock *bblock;
6170         const MonoOpcode *opcode;
6171
6172         while (ip < end) {
6173                 cli_addr = ip - start;
6174                 i = mono_opcode_value ((const guint8 **)&ip, end);
6175                 if (i < 0)
6176                         UNVERIFIED;
6177                 opcode = &mono_opcodes [i];
6178                 switch (opcode->argument) {
6179                 case MonoInlineNone:
6180                         ip++; 
6181                         break;
6182                 case MonoInlineString:
6183                 case MonoInlineType:
6184                 case MonoInlineField:
6185                 case MonoInlineMethod:
6186                 case MonoInlineTok:
6187                 case MonoInlineSig:
6188                 case MonoShortInlineR:
6189                 case MonoInlineI:
6190                         ip += 5;
6191                         break;
6192                 case MonoInlineVar:
6193                         ip += 3;
6194                         break;
6195                 case MonoShortInlineVar:
6196                 case MonoShortInlineI:
6197                         ip += 2;
6198                         break;
6199                 case MonoShortInlineBrTarget:
6200                         target = start + cli_addr + 2 + (signed char)ip [1];
6201                         GET_BBLOCK (cfg, bblock, target);
6202                         ip += 2;
6203                         if (ip < end)
6204                                 GET_BBLOCK (cfg, bblock, ip);
6205                         break;
6206                 case MonoInlineBrTarget:
6207                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6208                         GET_BBLOCK (cfg, bblock, target);
6209                         ip += 5;
6210                         if (ip < end)
6211                                 GET_BBLOCK (cfg, bblock, ip);
6212                         break;
6213                 case MonoInlineSwitch: {
6214                         guint32 n = read32 (ip + 1);
6215                         guint32 j;
6216                         ip += 5;
6217                         cli_addr += 5 + 4 * n;
6218                         target = start + cli_addr;
6219                         GET_BBLOCK (cfg, bblock, target);
6220                         
6221                         for (j = 0; j < n; ++j) {
6222                                 target = start + cli_addr + (gint32)read32 (ip);
6223                                 GET_BBLOCK (cfg, bblock, target);
6224                                 ip += 4;
6225                         }
6226                         break;
6227                 }
6228                 case MonoInlineR:
6229                 case MonoInlineI8:
6230                         ip += 9;
6231                         break;
6232                 default:
6233                         g_assert_not_reached ();
6234                 }
6235
6236                 if (i == CEE_THROW) {
6237                         unsigned char *bb_start = ip - 1;
6238                         
6239                         /* Find the start of the bblock containing the throw */
6240                         bblock = NULL;
6241                         while ((bb_start >= start) && !bblock) {
6242                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6243                                 bb_start --;
6244                         }
6245                         if (bblock)
6246                                 bblock->out_of_line = 1;
6247                 }
6248         }
6249         return 0;
6250 unverified:
6251 exception_exit:
6252         *pos = ip;
6253         return 1;
6254 }
6255
6256 static inline MonoMethod *
6257 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6258 {
6259         MonoMethod *method;
6260
6261         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6262                 method = mono_method_get_wrapper_data (m, token);
6263                 if (context)
6264                         method = mono_class_inflate_generic_method (method, context);
6265         } else {
6266                 method = mono_get_method_full (m->klass->image, token, klass, context);
6267         }
6268
6269         return method;
6270 }
6271
6272 static inline MonoMethod *
6273 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6274 {
6275         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6276
6277         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6278                 return NULL;
6279
6280         return method;
6281 }
6282
6283 static inline MonoClass*
6284 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6285 {
6286         MonoClass *klass;
6287
6288         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6289                 klass = mono_method_get_wrapper_data (method, token);
6290                 if (context)
6291                         klass = mono_class_inflate_generic_class (klass, context);
6292         } else {
6293                 klass = mono_class_get_full (method->klass->image, token, context);
6294         }
6295         if (klass)
6296                 mono_class_init (klass);
6297         return klass;
6298 }
6299
6300 static inline MonoMethodSignature*
6301 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6302 {
6303         MonoMethodSignature *fsig;
6304
6305         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6306                 MonoError error;
6307
6308                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6309                 if (context) {
6310                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6311                         // FIXME:
6312                         g_assert (mono_error_ok (&error));
6313                 }
6314         } else {
6315                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6316         }
6317         return fsig;
6318 }
6319
6320 /*
6321  * Returns TRUE if the JIT should abort inlining because "callee"
6322  * is influenced by security attributes.
6323  */
6324 static
6325 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6326 {
6327         guint32 result;
6328         
6329         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6330                 return TRUE;
6331         }
6332         
6333         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6334         if (result == MONO_JIT_SECURITY_OK)
6335                 return FALSE;
6336
6337         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6338                 /* Generate code to throw a SecurityException before the actual call/link */
6339                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6340                 MonoInst *args [2];
6341
6342                 NEW_ICONST (cfg, args [0], 4);
6343                 NEW_METHODCONST (cfg, args [1], caller);
6344                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6345         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6346                  /* don't hide previous results */
6347                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6348                 cfg->exception_data = result;
6349                 return TRUE;
6350         }
6351         
6352         return FALSE;
6353 }
6354
6355 static MonoMethod*
6356 throw_exception (void)
6357 {
6358         static MonoMethod *method = NULL;
6359
6360         if (!method) {
6361                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6362                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6363         }
6364         g_assert (method);
6365         return method;
6366 }
6367
6368 static void
6369 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6370 {
6371         MonoMethod *thrower = throw_exception ();
6372         MonoInst *args [1];
6373
6374         EMIT_NEW_PCONST (cfg, args [0], ex);
6375         mono_emit_method_call (cfg, thrower, args, NULL);
6376 }
6377
6378 /*
6379  * Return the original method is a wrapper is specified. We can only access 
6380  * the custom attributes from the original method.
6381  */
6382 static MonoMethod*
6383 get_original_method (MonoMethod *method)
6384 {
6385         if (method->wrapper_type == MONO_WRAPPER_NONE)
6386                 return method;
6387
6388         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6389         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6390                 return NULL;
6391
6392         /* in other cases we need to find the original method */
6393         return mono_marshal_method_from_wrapper (method);
6394 }
6395
6396 static void
6397 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6398                                           MonoBasicBlock *bblock, unsigned char *ip)
6399 {
6400         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6401         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6402         if (ex)
6403                 emit_throw_exception (cfg, ex);
6404 }
6405
6406 static void
6407 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6408                                          MonoBasicBlock *bblock, unsigned char *ip)
6409 {
6410         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6411         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6412         if (ex)
6413                 emit_throw_exception (cfg, ex);
6414 }
6415
6416 /*
6417  * Check that the IL instructions at ip are the array initialization
6418  * sequence and return the pointer to the data and the size.
6419  */
6420 static const char*
6421 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6422 {
6423         /*
6424          * newarr[System.Int32]
6425          * dup
6426          * ldtoken field valuetype ...
6427          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6428          */
6429         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6430                 guint32 token = read32 (ip + 7);
6431                 guint32 field_token = read32 (ip + 2);
6432                 guint32 field_index = field_token & 0xffffff;
6433                 guint32 rva;
6434                 const char *data_ptr;
6435                 int size = 0;
6436                 MonoMethod *cmethod;
6437                 MonoClass *dummy_class;
6438                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6439                 int dummy_align;
6440
6441                 if (!field)
6442                         return NULL;
6443
6444                 *out_field_token = field_token;
6445
6446                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6447                 if (!cmethod)
6448                         return NULL;
6449                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6450                         return NULL;
6451                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6452                 case MONO_TYPE_BOOLEAN:
6453                 case MONO_TYPE_I1:
6454                 case MONO_TYPE_U1:
6455                         size = 1; break;
6456                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6457 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6458                 case MONO_TYPE_CHAR:
6459                 case MONO_TYPE_I2:
6460                 case MONO_TYPE_U2:
6461                         size = 2; break;
6462                 case MONO_TYPE_I4:
6463                 case MONO_TYPE_U4:
6464                 case MONO_TYPE_R4:
6465                         size = 4; break;
6466                 case MONO_TYPE_R8:
6467                 case MONO_TYPE_I8:
6468                 case MONO_TYPE_U8:
6469                         size = 8; break;
6470 #endif
6471                 default:
6472                         return NULL;
6473                 }
6474                 size *= len;
6475                 if (size > mono_type_size (field->type, &dummy_align))
6476                     return NULL;
6477                 *out_size = size;
6478                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6479                 if (!method->klass->image->dynamic) {
6480                         field_index = read32 (ip + 2) & 0xffffff;
6481                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6482                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6483                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6484                         /* for aot code we do the lookup on load */
6485                         if (aot && data_ptr)
6486                                 return GUINT_TO_POINTER (rva);
6487                 } else {
6488                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6489                         g_assert (!aot);
6490                         data_ptr = mono_field_get_data (field);
6491                 }
6492                 return data_ptr;
6493         }
6494         return NULL;
6495 }
6496
6497 static void
6498 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6499 {
6500         char *method_fname = mono_method_full_name (method, TRUE);
6501         char *method_code;
6502         MonoMethodHeader *header = mono_method_get_header (method);
6503
6504         if (header->code_size == 0)
6505                 method_code = g_strdup ("method body is empty.");
6506         else
6507                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6508         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6509         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6510         g_free (method_fname);
6511         g_free (method_code);
6512         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6513 }
6514
6515 static void
6516 set_exception_object (MonoCompile *cfg, MonoException *exception)
6517 {
6518         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6519         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6520         cfg->exception_ptr = exception;
6521 }
6522
6523 static void
6524 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6525 {
6526         MonoInst *ins;
6527         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6528         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6529                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6530                 /* Optimize reg-reg moves away */
6531                 /* 
6532                  * Can't optimize other opcodes, since sp[0] might point to
6533                  * the last ins of a decomposed opcode.
6534                  */
6535                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6536         } else {
6537                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6538         }
6539 }
6540
6541 /*
6542  * ldloca inhibits many optimizations so try to get rid of it in common
6543  * cases.
6544  */
6545 static inline unsigned char *
6546 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6547 {
6548         int local, token;
6549         MonoClass *klass;
6550         MonoType *type;
6551
6552         if (size == 1) {
6553                 local = ip [1];
6554                 ip += 2;
6555         } else {
6556                 local = read16 (ip + 2);
6557                 ip += 4;
6558         }
6559         
6560         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6561                 /* From the INITOBJ case */
6562                 token = read32 (ip + 2);
6563                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6564                 CHECK_TYPELOAD (klass);
6565                 type = mini_replace_type (&klass->byval_arg);
6566                 emit_init_local (cfg, local, type, TRUE);
6567                 return ip + 6;
6568         }
6569 load_error:
6570         return NULL;
6571 }
6572
6573 static gboolean
6574 is_exception_class (MonoClass *class)
6575 {
6576         while (class) {
6577                 if (class == mono_defaults.exception_class)
6578                         return TRUE;
6579                 class = class->parent;
6580         }
6581         return FALSE;
6582 }
6583
6584 /*
6585  * is_jit_optimizer_disabled:
6586  *
6587  *   Determine whenever M's assembly has a DebuggableAttribute with the
6588  * IsJITOptimizerDisabled flag set.
6589  */
6590 static gboolean
6591 is_jit_optimizer_disabled (MonoMethod *m)
6592 {
6593         MonoAssembly *ass = m->klass->image->assembly;
6594         MonoCustomAttrInfo* attrs;
6595         static MonoClass *klass;
6596         int i;
6597         gboolean val = FALSE;
6598
6599         g_assert (ass);
6600         if (ass->jit_optimizer_disabled_inited)
6601                 return ass->jit_optimizer_disabled;
6602
6603         if (!klass)
6604                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6605         if (!klass) {
6606                 /* Linked away */
6607                 ass->jit_optimizer_disabled = FALSE;
6608                 mono_memory_barrier ();
6609                 ass->jit_optimizer_disabled_inited = TRUE;
6610                 return FALSE;
6611         }
6612
6613         attrs = mono_custom_attrs_from_assembly (ass);
6614         if (attrs) {
6615                 for (i = 0; i < attrs->num_attrs; ++i) {
6616                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6617                         const gchar *p;
6618                         int len;
6619                         MonoMethodSignature *sig;
6620
6621                         if (!attr->ctor || attr->ctor->klass != klass)
6622                                 continue;
6623                         /* Decode the attribute. See reflection.c */
6624                         len = attr->data_size;
6625                         p = (const char*)attr->data;
6626                         g_assert (read16 (p) == 0x0001);
6627                         p += 2;
6628
6629                         // FIXME: Support named parameters
6630                         sig = mono_method_signature (attr->ctor);
6631                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6632                                 continue;
6633                         /* Two boolean arguments */
6634                         p ++;
6635                         val = *p;
6636                 }
6637                 mono_custom_attrs_free (attrs);
6638         }
6639
6640         ass->jit_optimizer_disabled = val;
6641         mono_memory_barrier ();
6642         ass->jit_optimizer_disabled_inited = TRUE;
6643
6644         return val;
6645 }
6646
6647 static gboolean
6648 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6649 {
6650         gboolean supported_tail_call;
6651         int i;
6652
6653 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6654         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6655 #else
6656         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6657 #endif
6658
6659         for (i = 0; i < fsig->param_count; ++i) {
6660                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6661                         /* These can point to the current method's stack */
6662                         supported_tail_call = FALSE;
6663         }
6664         if (fsig->hasthis && cmethod->klass->valuetype)
6665                 /* this might point to the current method's stack */
6666                 supported_tail_call = FALSE;
6667         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6668                 supported_tail_call = FALSE;
6669         if (cfg->method->save_lmf)
6670                 supported_tail_call = FALSE;
6671         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6672                 supported_tail_call = FALSE;
6673         if (call_opcode != CEE_CALL)
6674                 supported_tail_call = FALSE;
6675
6676         /* Debugging support */
6677 #if 0
6678         if (supported_tail_call) {
6679                 if (!mono_debug_count ())
6680                         supported_tail_call = FALSE;
6681         }
6682 #endif
6683
6684         return supported_tail_call;
6685 }
6686
6687 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6688  * it to the thread local value based on the tls_offset field. Every other kind of access to
6689  * the field causes an assert.
6690  */
6691 static gboolean
6692 is_magic_tls_access (MonoClassField *field)
6693 {
6694         if (strcmp (field->name, "tlsdata"))
6695                 return FALSE;
6696         if (strcmp (field->parent->name, "ThreadLocal`1"))
6697                 return FALSE;
6698         return field->parent->image == mono_defaults.corlib;
6699 }
6700
6701 /* emits the code needed to access a managed tls var (like ThreadStatic)
6702  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6703  * pointer for the current thread.
6704  * Returns the MonoInst* representing the address of the tls var.
6705  */
6706 static MonoInst*
6707 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6708 {
6709         MonoInst *addr;
6710         int static_data_reg, array_reg, dreg;
6711         int offset2_reg, idx_reg;
6712         // inlined access to the tls data
6713         // idx = (offset >> 24) - 1;
6714         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6715         static_data_reg = alloc_ireg (cfg);
6716         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6717         idx_reg = alloc_ireg (cfg);
6718         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6719         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6720         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6721         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6722         array_reg = alloc_ireg (cfg);
6723         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6724         offset2_reg = alloc_ireg (cfg);
6725         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6726         dreg = alloc_ireg (cfg);
6727         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6728         return addr;
6729 }
6730
6731 /*
6732  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6733  * this address is cached per-method in cached_tls_addr.
6734  */
6735 static MonoInst*
6736 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6737 {
6738         MonoInst *load, *addr, *temp, *store, *thread_ins;
6739         MonoClassField *offset_field;
6740
6741         if (*cached_tls_addr) {
6742                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6743                 return addr;
6744         }
6745         thread_ins = mono_get_thread_intrinsic (cfg);
6746         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6747
6748         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6749         if (thread_ins) {
6750                 MONO_ADD_INS (cfg->cbb, thread_ins);
6751         } else {
6752                 MonoMethod *thread_method;
6753                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6754                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6755         }
6756         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6757         addr->klass = mono_class_from_mono_type (tls_field->type);
6758         addr->type = STACK_MP;
6759         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6760         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6761
6762         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6763         return addr;
6764 }
6765
6766 /*
6767  * mono_method_to_ir:
6768  *
6769  *   Translate the .net IL into linear IR.
6770  */
6771 int
6772 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6773                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6774                    guint inline_offset, gboolean is_virtual_call)
6775 {
6776         MonoError error;
6777         MonoInst *ins, **sp, **stack_start;
6778         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6779         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6780         MonoMethod *cmethod, *method_definition;
6781         MonoInst **arg_array;
6782         MonoMethodHeader *header;
6783         MonoImage *image;
6784         guint32 token, ins_flag;
6785         MonoClass *klass;
6786         MonoClass *constrained_call = NULL;
6787         unsigned char *ip, *end, *target, *err_pos;
6788         MonoMethodSignature *sig;
6789         MonoGenericContext *generic_context = NULL;
6790         MonoGenericContainer *generic_container = NULL;
6791         MonoType **param_types;
6792         int i, n, start_new_bblock, dreg;
6793         int num_calls = 0, inline_costs = 0;
6794         int breakpoint_id = 0;
6795         guint num_args;
6796         MonoBoolean security, pinvoke;
6797         MonoSecurityManager* secman = NULL;
6798         MonoDeclSecurityActions actions;
6799         GSList *class_inits = NULL;
6800         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6801         int context_used;
6802         gboolean init_locals, seq_points, skip_dead_blocks;
6803         gboolean disable_inline, sym_seq_points = FALSE;
6804         MonoInst *cached_tls_addr = NULL;
6805         MonoDebugMethodInfo *minfo;
6806         MonoBitSet *seq_point_locs = NULL;
6807         MonoBitSet *seq_point_set_locs = NULL;
6808
6809         disable_inline = is_jit_optimizer_disabled (method);
6810
6811         /* serialization and xdomain stuff may need access to private fields and methods */
6812         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6813         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6814         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6815         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6816         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6817         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6818
6819         dont_verify |= mono_security_smcs_hack_enabled ();
6820
6821         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6822         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6823         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6824         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6825         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6826
6827         image = method->klass->image;
6828         header = mono_method_get_header (method);
6829         if (!header) {
6830                 MonoLoaderError *error;
6831
6832                 if ((error = mono_loader_get_last_error ())) {
6833                         mono_cfg_set_exception (cfg, error->exception_type);
6834                 } else {
6835                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6836                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6837                 }
6838                 goto exception_exit;
6839         }
6840         generic_container = mono_method_get_generic_container (method);
6841         sig = mono_method_signature (method);
6842         num_args = sig->hasthis + sig->param_count;
6843         ip = (unsigned char*)header->code;
6844         cfg->cil_start = ip;
6845         end = ip + header->code_size;
6846         cfg->stat_cil_code_size += header->code_size;
6847
6848         seq_points = cfg->gen_seq_points && cfg->method == method;
6849 #ifdef PLATFORM_ANDROID
6850         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6851 #endif
6852
6853         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6854                 /* We could hit a seq point before attaching to the JIT (#8338) */
6855                 seq_points = FALSE;
6856         }
6857
6858         if (cfg->gen_seq_points && cfg->method == method) {
6859                 minfo = mono_debug_lookup_method (method);
6860                 if (minfo) {
6861                         int i, n_il_offsets;
6862                         int *il_offsets;
6863                         int *line_numbers;
6864
6865                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6866                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6867                         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);
6868                         sym_seq_points = TRUE;
6869                         for (i = 0; i < n_il_offsets; ++i) {
6870                                 if (il_offsets [i] < header->code_size)
6871                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6872                         }
6873                         g_free (il_offsets);
6874                         g_free (line_numbers);
6875                 }
6876         }
6877
6878         /* 
6879          * Methods without init_locals set could cause asserts in various passes
6880          * (#497220). To work around this, we emit dummy initialization opcodes
6881          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
6882          * on some platforms.
6883          */
6884         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
6885                 init_locals = header->init_locals;
6886         else
6887                 init_locals = TRUE;
6888
6889         method_definition = method;
6890         while (method_definition->is_inflated) {
6891                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6892                 method_definition = imethod->declaring;
6893         }
6894
6895         /* SkipVerification is not allowed if core-clr is enabled */
6896         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6897                 dont_verify = TRUE;
6898                 dont_verify_stloc = TRUE;
6899         }
6900
6901         if (sig->is_inflated)
6902                 generic_context = mono_method_get_context (method);
6903         else if (generic_container)
6904                 generic_context = &generic_container->context;
6905         cfg->generic_context = generic_context;
6906
6907         if (!cfg->generic_sharing_context)
6908                 g_assert (!sig->has_type_parameters);
6909
6910         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6911                 g_assert (method->is_inflated);
6912                 g_assert (mono_method_get_context (method)->method_inst);
6913         }
6914         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6915                 g_assert (sig->generic_param_count);
6916
6917         if (cfg->method == method) {
6918                 cfg->real_offset = 0;
6919         } else {
6920                 cfg->real_offset = inline_offset;
6921         }
6922
6923         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6924         cfg->cil_offset_to_bb_len = header->code_size;
6925
6926         cfg->current_method = method;
6927
6928         if (cfg->verbose_level > 2)
6929                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6930
6931         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6932         if (sig->hasthis)
6933                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6934         for (n = 0; n < sig->param_count; ++n)
6935                 param_types [n + sig->hasthis] = sig->params [n];
6936         cfg->arg_types = param_types;
6937
6938         dont_inline = g_list_prepend (dont_inline, method);
6939         if (cfg->method == method) {
6940
6941                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6942                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6943
6944                 /* ENTRY BLOCK */
6945                 NEW_BBLOCK (cfg, start_bblock);
6946                 cfg->bb_entry = start_bblock;
6947                 start_bblock->cil_code = NULL;
6948                 start_bblock->cil_length = 0;
6949 #if defined(__native_client_codegen__)
6950                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6951                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6952                 MONO_ADD_INS (start_bblock, ins);
6953 #endif
6954
6955                 /* EXIT BLOCK */
6956                 NEW_BBLOCK (cfg, end_bblock);
6957                 cfg->bb_exit = end_bblock;
6958                 end_bblock->cil_code = NULL;
6959                 end_bblock->cil_length = 0;
6960                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6961                 g_assert (cfg->num_bblocks == 2);
6962
6963                 arg_array = cfg->args;
6964
6965                 if (header->num_clauses) {
6966                         cfg->spvars = g_hash_table_new (NULL, NULL);
6967                         cfg->exvars = g_hash_table_new (NULL, NULL);
6968                 }
6969                 /* handle exception clauses */
6970                 for (i = 0; i < header->num_clauses; ++i) {
6971                         MonoBasicBlock *try_bb;
6972                         MonoExceptionClause *clause = &header->clauses [i];
6973                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6974                         try_bb->real_offset = clause->try_offset;
6975                         try_bb->try_start = TRUE;
6976                         try_bb->region = ((i + 1) << 8) | clause->flags;
6977                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6978                         tblock->real_offset = clause->handler_offset;
6979                         tblock->flags |= BB_EXCEPTION_HANDLER;
6980
6981                         /*
6982                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6983                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
6984                          */
6985                         if (COMPILE_LLVM (cfg))
6986                                 link_bblock (cfg, try_bb, tblock);
6987
6988                         if (*(ip + clause->handler_offset) == CEE_POP)
6989                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6990
6991                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6992                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6993                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6994                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6995                                 MONO_ADD_INS (tblock, ins);
6996
6997                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6998                                         /* finally clauses already have a seq point */
6999                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7000                                         MONO_ADD_INS (tblock, ins);
7001                                 }
7002
7003                                 /* todo: is a fault block unsafe to optimize? */
7004                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7005                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7006                         }
7007
7008
7009                         /*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);
7010                           while (p < end) {
7011                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7012                           }*/
7013                         /* catch and filter blocks get the exception object on the stack */
7014                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7015                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7016                                 MonoInst *dummy_use;
7017
7018                                 /* mostly like handle_stack_args (), but just sets the input args */
7019                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7020                                 tblock->in_scount = 1;
7021                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7022                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7023
7024                                 /* 
7025                                  * Add a dummy use for the exvar so its liveness info will be
7026                                  * correct.
7027                                  */
7028                                 cfg->cbb = tblock;
7029                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7030                                 
7031                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7032                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7033                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7034                                         tblock->real_offset = clause->data.filter_offset;
7035                                         tblock->in_scount = 1;
7036                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7037                                         /* The filter block shares the exvar with the handler block */
7038                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7039                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7040                                         MONO_ADD_INS (tblock, ins);
7041                                 }
7042                         }
7043
7044                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7045                                         clause->data.catch_class &&
7046                                         cfg->generic_sharing_context &&
7047                                         mono_class_check_context_used (clause->data.catch_class)) {
7048                                 /*
7049                                  * In shared generic code with catch
7050                                  * clauses containing type variables
7051                                  * the exception handling code has to
7052                                  * be able to get to the rgctx.
7053                                  * Therefore we have to make sure that
7054                                  * the vtable/mrgctx argument (for
7055                                  * static or generic methods) or the
7056                                  * "this" argument (for non-static
7057                                  * methods) are live.
7058                                  */
7059                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7060                                                 mini_method_get_context (method)->method_inst ||
7061                                                 method->klass->valuetype) {
7062                                         mono_get_vtable_var (cfg);
7063                                 } else {
7064                                         MonoInst *dummy_use;
7065
7066                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7067                                 }
7068                         }
7069                 }
7070         } else {
7071                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7072                 cfg->cbb = start_bblock;
7073                 cfg->args = arg_array;
7074                 mono_save_args (cfg, sig, inline_args);
7075         }
7076
7077         /* FIRST CODE BLOCK */
7078         NEW_BBLOCK (cfg, bblock);
7079         bblock->cil_code = ip;
7080         cfg->cbb = bblock;
7081         cfg->ip = ip;
7082
7083         ADD_BBLOCK (cfg, bblock);
7084
7085         if (cfg->method == method) {
7086                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7087                 if (breakpoint_id) {
7088                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7089                         MONO_ADD_INS (bblock, ins);
7090                 }
7091         }
7092
7093         if (mono_security_cas_enabled ())
7094                 secman = mono_security_manager_get_methods ();
7095
7096         security = (secman && mono_security_method_has_declsec (method));
7097         /* at this point having security doesn't mean we have any code to generate */
7098         if (security && (cfg->method == method)) {
7099                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7100                  * And we do not want to enter the next section (with allocation) if we
7101                  * have nothing to generate */
7102                 security = mono_declsec_get_demands (method, &actions);
7103         }
7104
7105         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7106         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7107         if (pinvoke) {
7108                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7109                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7110                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7111
7112                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7113                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7114                                 pinvoke = FALSE;
7115                         }
7116                         if (custom)
7117                                 mono_custom_attrs_free (custom);
7118
7119                         if (pinvoke) {
7120                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7121                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7122                                         pinvoke = FALSE;
7123                                 }
7124                                 if (custom)
7125                                         mono_custom_attrs_free (custom);
7126                         }
7127                 } else {
7128                         /* not a P/Invoke after all */
7129                         pinvoke = FALSE;
7130                 }
7131         }
7132         
7133         /* we use a separate basic block for the initialization code */
7134         NEW_BBLOCK (cfg, init_localsbb);
7135         cfg->bb_init = init_localsbb;
7136         init_localsbb->real_offset = cfg->real_offset;
7137         start_bblock->next_bb = init_localsbb;
7138         init_localsbb->next_bb = bblock;
7139         link_bblock (cfg, start_bblock, init_localsbb);
7140         link_bblock (cfg, init_localsbb, bblock);
7141                 
7142         cfg->cbb = init_localsbb;
7143
7144         if (cfg->gsharedvt && cfg->method == method) {
7145                 MonoGSharedVtMethodInfo *info;
7146                 MonoInst *var, *locals_var;
7147                 int dreg;
7148
7149                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7150                 info->method = cfg->method;
7151                 info->count_entries = 16;
7152                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7153                 cfg->gsharedvt_info = info;
7154
7155                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7156                 /* prevent it from being register allocated */
7157                 //var->flags |= MONO_INST_VOLATILE;
7158                 cfg->gsharedvt_info_var = var;
7159
7160                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7161                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7162
7163                 /* Allocate locals */
7164                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7165                 /* prevent it from being register allocated */
7166                 //locals_var->flags |= MONO_INST_VOLATILE;
7167                 cfg->gsharedvt_locals_var = locals_var;
7168
7169                 dreg = alloc_ireg (cfg);
7170                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7171
7172                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7173                 ins->dreg = locals_var->dreg;
7174                 ins->sreg1 = dreg;
7175                 MONO_ADD_INS (cfg->cbb, ins);
7176                 cfg->gsharedvt_locals_var_ins = ins;
7177                 
7178                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7179                 /*
7180                 if (init_locals)
7181                         ins->flags |= MONO_INST_INIT;
7182                 */
7183         }
7184
7185         /* at this point we know, if security is TRUE, that some code needs to be generated */
7186         if (security && (cfg->method == method)) {
7187                 MonoInst *args [2];
7188
7189                 cfg->stat_cas_demand_generation++;
7190
7191                 if (actions.demand.blob) {
7192                         /* Add code for SecurityAction.Demand */
7193                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7194                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7195                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7196                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7197                 }
7198                 if (actions.noncasdemand.blob) {
7199                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7200                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7201                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7202                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7203                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7204                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7205                 }
7206                 if (actions.demandchoice.blob) {
7207                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7208                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7209                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7210                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7211                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7212                 }
7213         }
7214
7215         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7216         if (pinvoke) {
7217                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7218         }
7219
7220         if (mono_security_core_clr_enabled ()) {
7221                 /* check if this is native code, e.g. an icall or a p/invoke */
7222                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7223                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7224                         if (wrapped) {
7225                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7226                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7227
7228                                 /* if this ia a native call then it can only be JITted from platform code */
7229                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7230                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7231                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7232                                                         mono_get_exception_method_access ();
7233                                                 emit_throw_exception (cfg, ex);
7234                                         }
7235                                 }
7236                         }
7237                 }
7238         }
7239
7240         CHECK_CFG_EXCEPTION;
7241
7242         if (header->code_size == 0)
7243                 UNVERIFIED;
7244
7245         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7246                 ip = err_pos;
7247                 UNVERIFIED;
7248         }
7249
7250         if (cfg->method == method)
7251                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7252
7253         for (n = 0; n < header->num_locals; ++n) {
7254                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7255                         UNVERIFIED;
7256         }
7257         class_inits = NULL;
7258
7259         /* We force the vtable variable here for all shared methods
7260            for the possibility that they might show up in a stack
7261            trace where their exact instantiation is needed. */
7262         if (cfg->generic_sharing_context && method == cfg->method) {
7263                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7264                                 mini_method_get_context (method)->method_inst ||
7265                                 method->klass->valuetype) {
7266                         mono_get_vtable_var (cfg);
7267                 } else {
7268                         /* FIXME: Is there a better way to do this?
7269                            We need the variable live for the duration
7270                            of the whole method. */
7271                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7272                 }
7273         }
7274
7275         /* add a check for this != NULL to inlined methods */
7276         if (is_virtual_call) {
7277                 MonoInst *arg_ins;
7278
7279                 NEW_ARGLOAD (cfg, arg_ins, 0);
7280                 MONO_ADD_INS (cfg->cbb, arg_ins);
7281                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7282         }
7283
7284         skip_dead_blocks = !dont_verify;
7285         if (skip_dead_blocks) {
7286                 original_bb = bb = mono_basic_block_split (method, &error);
7287                 if (!mono_error_ok (&error)) {
7288                         mono_error_cleanup (&error);
7289                         UNVERIFIED;
7290                 }
7291                 g_assert (bb);
7292         }
7293
7294         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7295         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7296
7297         ins_flag = 0;
7298         start_new_bblock = 0;
7299         cfg->cbb = bblock;
7300         while (ip < end) {
7301                 if (cfg->method == method)
7302                         cfg->real_offset = ip - header->code;
7303                 else
7304                         cfg->real_offset = inline_offset;
7305                 cfg->ip = ip;
7306
7307                 context_used = 0;
7308                 
7309                 if (start_new_bblock) {
7310                         bblock->cil_length = ip - bblock->cil_code;
7311                         if (start_new_bblock == 2) {
7312                                 g_assert (ip == tblock->cil_code);
7313                         } else {
7314                                 GET_BBLOCK (cfg, tblock, ip);
7315                         }
7316                         bblock->next_bb = tblock;
7317                         bblock = tblock;
7318                         cfg->cbb = bblock;
7319                         start_new_bblock = 0;
7320                         for (i = 0; i < bblock->in_scount; ++i) {
7321                                 if (cfg->verbose_level > 3)
7322                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7323                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7324                                 *sp++ = ins;
7325                         }
7326                         if (class_inits)
7327                                 g_slist_free (class_inits);
7328                         class_inits = NULL;
7329                 } else {
7330                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7331                                 link_bblock (cfg, bblock, tblock);
7332                                 if (sp != stack_start) {
7333                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7334                                         sp = stack_start;
7335                                         CHECK_UNVERIFIABLE (cfg);
7336                                 }
7337                                 bblock->next_bb = tblock;
7338                                 bblock = tblock;
7339                                 cfg->cbb = bblock;
7340                                 for (i = 0; i < bblock->in_scount; ++i) {
7341                                         if (cfg->verbose_level > 3)
7342                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7343                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7344                                         *sp++ = ins;
7345                                 }
7346                                 g_slist_free (class_inits);
7347                                 class_inits = NULL;
7348                         }
7349                 }
7350
7351                 if (skip_dead_blocks) {
7352                         int ip_offset = ip - header->code;
7353
7354                         if (ip_offset == bb->end)
7355                                 bb = bb->next;
7356
7357                         if (bb->dead) {
7358                                 int op_size = mono_opcode_size (ip, end);
7359                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7360
7361                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7362
7363                                 if (ip_offset + op_size == bb->end) {
7364                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7365                                         MONO_ADD_INS (bblock, ins);
7366                                         start_new_bblock = 1;
7367                                 }
7368
7369                                 ip += op_size;
7370                                 continue;
7371                         }
7372                 }
7373                 /*
7374                  * Sequence points are points where the debugger can place a breakpoint.
7375                  * Currently, we generate these automatically at points where the IL
7376                  * stack is empty.
7377                  */
7378                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7379                         /*
7380                          * Make methods interruptable at the beginning, and at the targets of
7381                          * backward branches.
7382                          * Also, do this at the start of every bblock in methods with clauses too,
7383                          * to be able to handle instructions with inprecise control flow like
7384                          * throw/endfinally.
7385                          * Backward branches are handled at the end of method-to-ir ().
7386                          */
7387                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7388
7389                         /* Avoid sequence points on empty IL like .volatile */
7390                         // FIXME: Enable this
7391                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7392                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7393                         if (sp != stack_start)
7394                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7395                         MONO_ADD_INS (cfg->cbb, ins);
7396
7397                         if (sym_seq_points)
7398                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7399                 }
7400
7401                 bblock->real_offset = cfg->real_offset;
7402
7403                 if ((cfg->method == method) && cfg->coverage_info) {
7404                         guint32 cil_offset = ip - header->code;
7405                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7406
7407                         /* TODO: Use an increment here */
7408 #if defined(TARGET_X86)
7409                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7410                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7411                         ins->inst_imm = 1;
7412                         MONO_ADD_INS (cfg->cbb, ins);
7413 #else
7414                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7415                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7416 #endif
7417                 }
7418
7419                 if (cfg->verbose_level > 3)
7420                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7421
7422                 switch (*ip) {
7423                 case CEE_NOP:
7424                         if (seq_points && !sym_seq_points && sp != stack_start) {
7425                                 /*
7426                                  * The C# compiler uses these nops to notify the JIT that it should
7427                                  * insert seq points.
7428                                  */
7429                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7430                                 MONO_ADD_INS (cfg->cbb, ins);
7431                         }
7432                         if (cfg->keep_cil_nops)
7433                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7434                         else
7435                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7436                         ip++;
7437                         MONO_ADD_INS (bblock, ins);
7438                         break;
7439                 case CEE_BREAK:
7440                         if (should_insert_brekpoint (cfg->method)) {
7441                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7442                         } else {
7443                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7444                         }
7445                         ip++;
7446                         MONO_ADD_INS (bblock, ins);
7447                         break;
7448                 case CEE_LDARG_0:
7449                 case CEE_LDARG_1:
7450                 case CEE_LDARG_2:
7451                 case CEE_LDARG_3:
7452                         CHECK_STACK_OVF (1);
7453                         n = (*ip)-CEE_LDARG_0;
7454                         CHECK_ARG (n);
7455                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7456                         ip++;
7457                         *sp++ = ins;
7458                         break;
7459                 case CEE_LDLOC_0:
7460                 case CEE_LDLOC_1:
7461                 case CEE_LDLOC_2:
7462                 case CEE_LDLOC_3:
7463                         CHECK_STACK_OVF (1);
7464                         n = (*ip)-CEE_LDLOC_0;
7465                         CHECK_LOCAL (n);
7466                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7467                         ip++;
7468                         *sp++ = ins;
7469                         break;
7470                 case CEE_STLOC_0:
7471                 case CEE_STLOC_1:
7472                 case CEE_STLOC_2:
7473                 case CEE_STLOC_3: {
7474                         CHECK_STACK (1);
7475                         n = (*ip)-CEE_STLOC_0;
7476                         CHECK_LOCAL (n);
7477                         --sp;
7478                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7479                                 UNVERIFIED;
7480                         emit_stloc_ir (cfg, sp, header, n);
7481                         ++ip;
7482                         inline_costs += 1;
7483                         break;
7484                         }
7485                 case CEE_LDARG_S:
7486                         CHECK_OPSIZE (2);
7487                         CHECK_STACK_OVF (1);
7488                         n = ip [1];
7489                         CHECK_ARG (n);
7490                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7491                         *sp++ = ins;
7492                         ip += 2;
7493                         break;
7494                 case CEE_LDARGA_S:
7495                         CHECK_OPSIZE (2);
7496                         CHECK_STACK_OVF (1);
7497                         n = ip [1];
7498                         CHECK_ARG (n);
7499                         NEW_ARGLOADA (cfg, ins, n);
7500                         MONO_ADD_INS (cfg->cbb, ins);
7501                         *sp++ = ins;
7502                         ip += 2;
7503                         break;
7504                 case CEE_STARG_S:
7505                         CHECK_OPSIZE (2);
7506                         CHECK_STACK (1);
7507                         --sp;
7508                         n = ip [1];
7509                         CHECK_ARG (n);
7510                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7511                                 UNVERIFIED;
7512                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7513                         ip += 2;
7514                         break;
7515                 case CEE_LDLOC_S:
7516                         CHECK_OPSIZE (2);
7517                         CHECK_STACK_OVF (1);
7518                         n = ip [1];
7519                         CHECK_LOCAL (n);
7520                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7521                         *sp++ = ins;
7522                         ip += 2;
7523                         break;
7524                 case CEE_LDLOCA_S: {
7525                         unsigned char *tmp_ip;
7526                         CHECK_OPSIZE (2);
7527                         CHECK_STACK_OVF (1);
7528                         CHECK_LOCAL (ip [1]);
7529
7530                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7531                                 ip = tmp_ip;
7532                                 inline_costs += 1;
7533                                 break;
7534                         }
7535
7536                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7537                         *sp++ = ins;
7538                         ip += 2;
7539                         break;
7540                 }
7541                 case CEE_STLOC_S:
7542                         CHECK_OPSIZE (2);
7543                         CHECK_STACK (1);
7544                         --sp;
7545                         CHECK_LOCAL (ip [1]);
7546                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7547                                 UNVERIFIED;
7548                         emit_stloc_ir (cfg, sp, header, ip [1]);
7549                         ip += 2;
7550                         inline_costs += 1;
7551                         break;
7552                 case CEE_LDNULL:
7553                         CHECK_STACK_OVF (1);
7554                         EMIT_NEW_PCONST (cfg, ins, NULL);
7555                         ins->type = STACK_OBJ;
7556                         ++ip;
7557                         *sp++ = ins;
7558                         break;
7559                 case CEE_LDC_I4_M1:
7560                         CHECK_STACK_OVF (1);
7561                         EMIT_NEW_ICONST (cfg, ins, -1);
7562                         ++ip;
7563                         *sp++ = ins;
7564                         break;
7565                 case CEE_LDC_I4_0:
7566                 case CEE_LDC_I4_1:
7567                 case CEE_LDC_I4_2:
7568                 case CEE_LDC_I4_3:
7569                 case CEE_LDC_I4_4:
7570                 case CEE_LDC_I4_5:
7571                 case CEE_LDC_I4_6:
7572                 case CEE_LDC_I4_7:
7573                 case CEE_LDC_I4_8:
7574                         CHECK_STACK_OVF (1);
7575                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7576                         ++ip;
7577                         *sp++ = ins;
7578                         break;
7579                 case CEE_LDC_I4_S:
7580                         CHECK_OPSIZE (2);
7581                         CHECK_STACK_OVF (1);
7582                         ++ip;
7583                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7584                         ++ip;
7585                         *sp++ = ins;
7586                         break;
7587                 case CEE_LDC_I4:
7588                         CHECK_OPSIZE (5);
7589                         CHECK_STACK_OVF (1);
7590                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7591                         ip += 5;
7592                         *sp++ = ins;
7593                         break;
7594                 case CEE_LDC_I8:
7595                         CHECK_OPSIZE (9);
7596                         CHECK_STACK_OVF (1);
7597                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7598                         ins->type = STACK_I8;
7599                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7600                         ++ip;
7601                         ins->inst_l = (gint64)read64 (ip);
7602                         MONO_ADD_INS (bblock, ins);
7603                         ip += 8;
7604                         *sp++ = ins;
7605                         break;
7606                 case CEE_LDC_R4: {
7607                         float *f;
7608                         gboolean use_aotconst = FALSE;
7609
7610 #ifdef TARGET_POWERPC
7611                         /* FIXME: Clean this up */
7612                         if (cfg->compile_aot)
7613                                 use_aotconst = TRUE;
7614 #endif
7615
7616                         /* FIXME: we should really allocate this only late in the compilation process */
7617                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7618                         CHECK_OPSIZE (5);
7619                         CHECK_STACK_OVF (1);
7620
7621                         if (use_aotconst) {
7622                                 MonoInst *cons;
7623                                 int dreg;
7624
7625                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7626
7627                                 dreg = alloc_freg (cfg);
7628                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7629                                 ins->type = STACK_R8;
7630                         } else {
7631                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7632                                 ins->type = STACK_R8;
7633                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7634                                 ins->inst_p0 = f;
7635                                 MONO_ADD_INS (bblock, ins);
7636                         }
7637                         ++ip;
7638                         readr4 (ip, f);
7639                         ip += 4;
7640                         *sp++ = ins;                    
7641                         break;
7642                 }
7643                 case CEE_LDC_R8: {
7644                         double *d;
7645                         gboolean use_aotconst = FALSE;
7646
7647 #ifdef TARGET_POWERPC
7648                         /* FIXME: Clean this up */
7649                         if (cfg->compile_aot)
7650                                 use_aotconst = TRUE;
7651 #endif
7652
7653                         /* FIXME: we should really allocate this only late in the compilation process */
7654                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7655                         CHECK_OPSIZE (9);
7656                         CHECK_STACK_OVF (1);
7657
7658                         if (use_aotconst) {
7659                                 MonoInst *cons;
7660                                 int dreg;
7661
7662                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7663
7664                                 dreg = alloc_freg (cfg);
7665                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7666                                 ins->type = STACK_R8;
7667                         } else {
7668                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7669                                 ins->type = STACK_R8;
7670                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7671                                 ins->inst_p0 = d;
7672                                 MONO_ADD_INS (bblock, ins);
7673                         }
7674                         ++ip;
7675                         readr8 (ip, d);
7676                         ip += 8;
7677                         *sp++ = ins;
7678                         break;
7679                 }
7680                 case CEE_DUP: {
7681                         MonoInst *temp, *store;
7682                         CHECK_STACK (1);
7683                         CHECK_STACK_OVF (1);
7684                         sp--;
7685                         ins = *sp;
7686
7687                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7688                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7689
7690                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7691                         *sp++ = ins;
7692
7693                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7694                         *sp++ = ins;
7695
7696                         ++ip;
7697                         inline_costs += 2;
7698                         break;
7699                 }
7700                 case CEE_POP:
7701                         CHECK_STACK (1);
7702                         ip++;
7703                         --sp;
7704
7705 #ifdef TARGET_X86
7706                         if (sp [0]->type == STACK_R8)
7707                                 /* we need to pop the value from the x86 FP stack */
7708                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7709 #endif
7710                         break;
7711                 case CEE_JMP: {
7712                         MonoCallInst *call;
7713
7714                         INLINE_FAILURE ("jmp");
7715                         GSHAREDVT_FAILURE (*ip);
7716
7717                         CHECK_OPSIZE (5);
7718                         if (stack_start != sp)
7719                                 UNVERIFIED;
7720                         token = read32 (ip + 1);
7721                         /* FIXME: check the signature matches */
7722                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7723
7724                         if (!cmethod || mono_loader_get_last_error ())
7725                                 LOAD_ERROR;
7726  
7727                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7728                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7729
7730                         if (mono_security_cas_enabled ())
7731                                 CHECK_CFG_EXCEPTION;
7732
7733                         if (ARCH_HAVE_OP_TAIL_CALL) {
7734                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7735                                 int i, n;
7736
7737                                 /* Handle tail calls similarly to calls */
7738                                 n = fsig->param_count + fsig->hasthis;
7739
7740                                 DISABLE_AOT (cfg);
7741
7742                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7743                                 call->method = cmethod;
7744                                 call->tail_call = TRUE;
7745                                 call->signature = mono_method_signature (cmethod);
7746                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7747                                 call->inst.inst_p0 = cmethod;
7748                                 for (i = 0; i < n; ++i)
7749                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7750
7751                                 mono_arch_emit_call (cfg, call);
7752                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7753                         } else {
7754                                 for (i = 0; i < num_args; ++i)
7755                                         /* Prevent arguments from being optimized away */
7756                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7757
7758                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7759                                 ins = (MonoInst*)call;
7760                                 ins->inst_p0 = cmethod;
7761                                 MONO_ADD_INS (bblock, ins);
7762                         }
7763
7764                         ip += 5;
7765                         start_new_bblock = 1;
7766                         break;
7767                 }
7768                 case CEE_CALLI:
7769                 case CEE_CALL:
7770                 case CEE_CALLVIRT: {
7771                         MonoInst *addr = NULL;
7772                         MonoMethodSignature *fsig = NULL;
7773                         int array_rank = 0;
7774                         int virtual = *ip == CEE_CALLVIRT;
7775                         int calli = *ip == CEE_CALLI;
7776                         gboolean pass_imt_from_rgctx = FALSE;
7777                         MonoInst *imt_arg = NULL;
7778                         MonoInst *keep_this_alive = NULL;
7779                         gboolean pass_vtable = FALSE;
7780                         gboolean pass_mrgctx = FALSE;
7781                         MonoInst *vtable_arg = NULL;
7782                         gboolean check_this = FALSE;
7783                         gboolean supported_tail_call = FALSE;
7784                         gboolean tail_call = FALSE;
7785                         gboolean need_seq_point = FALSE;
7786                         guint32 call_opcode = *ip;
7787                         gboolean emit_widen = TRUE;
7788                         gboolean push_res = TRUE;
7789                         gboolean skip_ret = FALSE;
7790                         gboolean delegate_invoke = FALSE;
7791
7792                         CHECK_OPSIZE (5);
7793                         token = read32 (ip + 1);
7794
7795                         ins = NULL;
7796
7797                         if (calli) {
7798                                 //GSHAREDVT_FAILURE (*ip);
7799                                 cmethod = NULL;
7800                                 CHECK_STACK (1);
7801                                 --sp;
7802                                 addr = *sp;
7803                                 fsig = mini_get_signature (method, token, generic_context);
7804                                 n = fsig->param_count + fsig->hasthis;
7805
7806                                 if (method->dynamic && fsig->pinvoke) {
7807                                         MonoInst *args [3];
7808
7809                                         /*
7810                                          * This is a call through a function pointer using a pinvoke
7811                                          * signature. Have to create a wrapper and call that instead.
7812                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7813                                          * instead based on the signature.
7814                                          */
7815                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7816                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7817                                         args [2] = addr;
7818                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7819                                 }
7820                         } else {
7821                                 MonoMethod *cil_method;
7822
7823                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7824                                 cil_method = cmethod;
7825                                 
7826                                 if (constrained_call) {
7827                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7828                                                 if (cfg->verbose_level > 2)
7829                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7830                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7831                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7832                                                           cfg->generic_sharing_context)) {
7833                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7834                                                 }
7835                                         } else {
7836                                                 if (cfg->verbose_level > 2)
7837                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7838
7839                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7840                                                         /* 
7841                                                          * This is needed since get_method_constrained can't find 
7842                                                          * the method in klass representing a type var.
7843                                                          * The type var is guaranteed to be a reference type in this
7844                                                          * case.
7845                                                          */
7846                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7847                                                                 g_assert (!cmethod->klass->valuetype);
7848                                                 } else {
7849                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7850                                                 }
7851                                         }
7852                                 }
7853                                         
7854                                 if (!cmethod || mono_loader_get_last_error ())
7855                                         LOAD_ERROR;
7856                                 if (!dont_verify && !cfg->skip_visibility) {
7857                                         MonoMethod *target_method = cil_method;
7858                                         if (method->is_inflated) {
7859                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7860                                         }
7861                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7862                                                 !mono_method_can_access_method (method, cil_method))
7863                                                 METHOD_ACCESS_FAILURE;
7864                                 }
7865
7866                                 if (mono_security_core_clr_enabled ())
7867                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7868
7869                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7870                                         /* MS.NET seems to silently convert this to a callvirt */
7871                                         virtual = 1;
7872
7873                                 {
7874                                         /*
7875                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7876                                          * converts to a callvirt.
7877                                          *
7878                                          * tests/bug-515884.il is an example of this behavior
7879                                          */
7880                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7881                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7882                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7883                                                 virtual = 1;
7884                                 }
7885
7886                                 if (!cmethod->klass->inited)
7887                                         if (!mono_class_init (cmethod->klass))
7888                                                 TYPE_LOAD_ERROR (cmethod->klass);
7889
7890                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7891                                     mini_class_is_system_array (cmethod->klass)) {
7892                                         array_rank = cmethod->klass->rank;
7893                                         fsig = mono_method_signature (cmethod);
7894                                 } else {
7895                                         fsig = mono_method_signature (cmethod);
7896
7897                                         if (!fsig)
7898                                                 LOAD_ERROR;
7899
7900                                         if (fsig->pinvoke) {
7901                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7902                                                         check_for_pending_exc, cfg->compile_aot);
7903                                                 fsig = mono_method_signature (wrapper);
7904                                         } else if (constrained_call) {
7905                                                 fsig = mono_method_signature (cmethod);
7906                                         } else {
7907                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7908                                         }
7909                                 }
7910
7911                                 mono_save_token_info (cfg, image, token, cil_method);
7912
7913                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7914                                         /*
7915                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7916                                          * foo (bar (), baz ())
7917                                          * works correctly. MS does this also:
7918                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7919                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7920                                          * even for simple cases, like:
7921                                          * int i = foo ();
7922                                          */
7923                                         /* Special case a few common successor opcodes */
7924                                         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)))
7925                                                 need_seq_point = TRUE;
7926                                 }
7927
7928                                 n = fsig->param_count + fsig->hasthis;
7929
7930                                 /* Don't support calls made using type arguments for now */
7931                                 /*
7932                                 if (cfg->gsharedvt) {
7933                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7934                                                 GSHAREDVT_FAILURE (*ip);
7935                                 }
7936                                 */
7937
7938                                 if (mono_security_cas_enabled ()) {
7939                                         if (check_linkdemand (cfg, method, cmethod))
7940                                                 INLINE_FAILURE ("linkdemand");
7941                                         CHECK_CFG_EXCEPTION;
7942                                 }
7943
7944                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7945                                         g_assert_not_reached ();
7946                         }
7947
7948                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7949                                 UNVERIFIED;
7950
7951                         if (!cfg->generic_sharing_context && cmethod)
7952                                 g_assert (!mono_method_check_context_used (cmethod));
7953
7954                         CHECK_STACK (n);
7955
7956                         //g_assert (!virtual || fsig->hasthis);
7957
7958                         sp -= n;
7959
7960                         if (constrained_call) {
7961                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7962                                         /*
7963                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7964                                          */
7965                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7966                                                 /* The 'Own method' case below */
7967                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7968                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7969                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7970                                                            (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)) &&
7971                                                            (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]))))) {
7972                                                 MonoInst *args [16];
7973
7974                                                 /*
7975                                                  * This case handles calls to
7976                                                  * - object:ToString()/Equals()/GetHashCode(),
7977                                                  * - System.IComparable<T>:CompareTo()
7978                                                  * - System.IEquatable<T>:Equals ()
7979                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7980                                                  */
7981
7982                                                 args [0] = sp [0];
7983                                                 if (mono_method_check_context_used (cmethod))
7984                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7985                                                 else
7986                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7987                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7988
7989                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7990                                                 if (fsig->hasthis && fsig->param_count) {
7991                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7992                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7993                                                         ins->dreg = alloc_preg (cfg);
7994                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7995                                                         MONO_ADD_INS (cfg->cbb, ins);
7996                                                         args [4] = ins;
7997
7998                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7999                                                                 int addr_reg;
8000
8001                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
8002
8003                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
8004                                                                 addr_reg = ins->dreg;
8005                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8006                                                         } else {
8007                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8008                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8009                                                         }
8010                                                 } else {
8011                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8012                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8013                                                 }
8014                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8015                                                 emit_widen = FALSE;
8016
8017                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8018                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8019                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
8020                                                         MonoInst *add;
8021
8022                                                         /* Unbox */
8023                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8024                                                         MONO_ADD_INS (cfg->cbb, add);
8025                                                         /* Load value */
8026                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8027                                                         MONO_ADD_INS (cfg->cbb, ins);
8028                                                         /* ins represents the call result */
8029                                                 }
8030
8031                                                 goto call_end;
8032                                         } else {
8033                                                 GSHAREDVT_FAILURE (*ip);
8034                                         }
8035                                 }
8036                                 /*
8037                                  * We have the `constrained.' prefix opcode.
8038                                  */
8039                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8040                                         /*
8041                                          * The type parameter is instantiated as a valuetype,
8042                                          * but that type doesn't override the method we're
8043                                          * calling, so we need to box `this'.
8044                                          */
8045                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8046                                         ins->klass = constrained_call;
8047                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8048                                         CHECK_CFG_EXCEPTION;
8049                                 } else if (!constrained_call->valuetype) {
8050                                         int dreg = alloc_ireg_ref (cfg);
8051
8052                                         /*
8053                                          * The type parameter is instantiated as a reference
8054                                          * type.  We have a managed pointer on the stack, so
8055                                          * we need to dereference it here.
8056                                          */
8057                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8058                                         ins->type = STACK_OBJ;
8059                                         sp [0] = ins;
8060                                 } else {
8061                                         if (cmethod->klass->valuetype) {
8062                                                 /* Own method */
8063                                         } else {
8064                                                 /* Interface method */
8065                                                 int ioffset, slot;
8066
8067                                                 mono_class_setup_vtable (constrained_call);
8068                                                 CHECK_TYPELOAD (constrained_call);
8069                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8070                                                 if (ioffset == -1)
8071                                                         TYPE_LOAD_ERROR (constrained_call);
8072                                                 slot = mono_method_get_vtable_slot (cmethod);
8073                                                 if (slot == -1)
8074                                                         TYPE_LOAD_ERROR (cmethod->klass);
8075                                                 cmethod = constrained_call->vtable [ioffset + slot];
8076
8077                                                 if (cmethod->klass == mono_defaults.enum_class) {
8078                                                         /* Enum implements some interfaces, so treat this as the first case */
8079                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8080                                                         ins->klass = constrained_call;
8081                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8082                                                         CHECK_CFG_EXCEPTION;
8083                                                 }
8084                                         }
8085                                         virtual = 0;
8086                                 }
8087                                 constrained_call = NULL;
8088                         }
8089
8090                         if (!calli && check_call_signature (cfg, fsig, sp))
8091                                 UNVERIFIED;
8092
8093 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8094                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8095                                 delegate_invoke = TRUE;
8096 #endif
8097
8098                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8099                                 bblock = cfg->cbb;
8100                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8101                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8102                                         emit_widen = FALSE;
8103                                 }
8104
8105                                 goto call_end;
8106                         }
8107
8108                         /* 
8109                          * If the callee is a shared method, then its static cctor
8110                          * might not get called after the call was patched.
8111                          */
8112                         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)) {
8113                                 emit_generic_class_init (cfg, cmethod->klass);
8114                                 CHECK_TYPELOAD (cmethod->klass);
8115                         }
8116
8117                         if (cmethod)
8118                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8119
8120                         if (cfg->generic_sharing_context && cmethod) {
8121                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8122
8123                                 context_used = mini_method_check_context_used (cfg, cmethod);
8124
8125                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8126                                         /* Generic method interface
8127                                            calls are resolved via a
8128                                            helper function and don't
8129                                            need an imt. */
8130                                         if (!cmethod_context || !cmethod_context->method_inst)
8131                                                 pass_imt_from_rgctx = TRUE;
8132                                 }
8133
8134                                 /*
8135                                  * If a shared method calls another
8136                                  * shared method then the caller must
8137                                  * have a generic sharing context
8138                                  * because the magic trampoline
8139                                  * requires it.  FIXME: We shouldn't
8140                                  * have to force the vtable/mrgctx
8141                                  * variable here.  Instead there
8142                                  * should be a flag in the cfg to
8143                                  * request a generic sharing context.
8144                                  */
8145                                 if (context_used &&
8146                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8147                                         mono_get_vtable_var (cfg);
8148                         }
8149
8150                         if (pass_vtable) {
8151                                 if (context_used) {
8152                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8153                                 } else {
8154                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8155
8156                                         CHECK_TYPELOAD (cmethod->klass);
8157                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8158                                 }
8159                         }
8160
8161                         if (pass_mrgctx) {
8162                                 g_assert (!vtable_arg);
8163
8164                                 if (!cfg->compile_aot) {
8165                                         /* 
8166                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8167                                          * for type load errors before.
8168                                          */
8169                                         mono_class_setup_vtable (cmethod->klass);
8170                                         CHECK_TYPELOAD (cmethod->klass);
8171                                 }
8172
8173                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8174
8175                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8176                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8177                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8178                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8179                                         if (virtual)
8180                                                 check_this = TRUE;
8181                                         virtual = 0;
8182                                 }
8183                         }
8184
8185                         if (pass_imt_from_rgctx) {
8186                                 g_assert (!pass_vtable);
8187                                 g_assert (cmethod);
8188
8189                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8190                                         cmethod, MONO_RGCTX_INFO_METHOD);
8191                         }
8192
8193                         if (check_this)
8194                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8195
8196                         /* Calling virtual generic methods */
8197                         if (cmethod && virtual && 
8198                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8199                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8200                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8201                             fsig->generic_param_count && 
8202                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8203                                 MonoInst *this_temp, *this_arg_temp, *store;
8204                                 MonoInst *iargs [4];
8205                                 gboolean use_imt = FALSE;
8206
8207                                 g_assert (fsig->is_inflated);
8208
8209                                 /* Prevent inlining of methods that contain indirect calls */
8210                                 INLINE_FAILURE ("virtual generic call");
8211
8212                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8213                                         GSHAREDVT_FAILURE (*ip);
8214
8215 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8216                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8217                                         use_imt = TRUE;
8218 #endif
8219
8220                                 if (use_imt) {
8221                                         g_assert (!imt_arg);
8222                                         if (!context_used)
8223                                                 g_assert (cmethod->is_inflated);
8224                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8225                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8226                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8227                                 } else {
8228                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8229                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8230                                         MONO_ADD_INS (bblock, store);
8231
8232                                         /* FIXME: This should be a managed pointer */
8233                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8234
8235                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8236                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8237                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8238                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8239                                         addr = mono_emit_jit_icall (cfg,
8240                                                                                                 mono_helper_compile_generic_method, iargs);
8241
8242                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8243
8244                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8245                                 }
8246
8247                                 goto call_end;
8248                         }
8249
8250                         /*
8251                          * Implement a workaround for the inherent races involved in locking:
8252                          * Monitor.Enter ()
8253                          * try {
8254                          * } finally {
8255                          *    Monitor.Exit ()
8256                          * }
8257                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8258                          * try block, the Exit () won't be executed, see:
8259                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8260                          * To work around this, we extend such try blocks to include the last x bytes
8261                          * of the Monitor.Enter () call.
8262                          */
8263                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8264                                 MonoBasicBlock *tbb;
8265
8266                                 GET_BBLOCK (cfg, tbb, ip + 5);
8267                                 /* 
8268                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8269                                  * from Monitor.Enter like ArgumentNullException.
8270                                  */
8271                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8272                                         /* Mark this bblock as needing to be extended */
8273                                         tbb->extend_try_block = TRUE;
8274                                 }
8275                         }
8276
8277                         /* Conversion to a JIT intrinsic */
8278                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8279                                 bblock = cfg->cbb;
8280                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8281                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8282                                         emit_widen = FALSE;
8283                                 }
8284                                 goto call_end;
8285                         }
8286
8287                         /* Inlining */
8288                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8289                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8290                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8291                                  !g_list_find (dont_inline, cmethod)) {
8292                                 int costs;
8293                                 gboolean always = FALSE;
8294
8295                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8296                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8297                                         /* Prevent inlining of methods that call wrappers */
8298                                         INLINE_FAILURE ("wrapper call");
8299                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8300                                         always = TRUE;
8301                                 }
8302
8303                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8304                                 if (costs) {
8305                                         cfg->real_offset += 5;
8306                                         bblock = cfg->cbb;
8307
8308                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8309                                                 /* *sp is already set by inline_method */
8310                                                 sp++;
8311                                                 push_res = FALSE;
8312                                         }
8313
8314                                         inline_costs += costs;
8315
8316                                         goto call_end;
8317                                 }
8318                         }
8319
8320                         /* Tail recursion elimination */
8321                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8322                                 gboolean has_vtargs = FALSE;
8323                                 int i;
8324
8325                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8326                                 INLINE_FAILURE ("tail call");
8327
8328                                 /* keep it simple */
8329                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8330                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8331                                                 has_vtargs = TRUE;
8332                                 }
8333
8334                                 if (!has_vtargs) {
8335                                         for (i = 0; i < n; ++i)
8336                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8337                                         MONO_INST_NEW (cfg, ins, OP_BR);
8338                                         MONO_ADD_INS (bblock, ins);
8339                                         tblock = start_bblock->out_bb [0];
8340                                         link_bblock (cfg, bblock, tblock);
8341                                         ins->inst_target_bb = tblock;
8342                                         start_new_bblock = 1;
8343
8344                                         /* skip the CEE_RET, too */
8345                                         if (ip_in_bb (cfg, bblock, ip + 5))
8346                                                 skip_ret = TRUE;
8347                                         push_res = FALSE;
8348                                         goto call_end;
8349                                 }
8350                         }
8351
8352                         inline_costs += 10 * num_calls++;
8353
8354                         /*
8355                          * Making generic calls out of gsharedvt methods.
8356                          */
8357                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8358                                 MonoRgctxInfoType info_type;
8359
8360                                 if (virtual) {
8361                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8362                                                 //GSHAREDVT_FAILURE (*ip);
8363                                         // disable for possible remoting calls
8364                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8365                                                 GSHAREDVT_FAILURE (*ip);
8366                                         if (fsig->generic_param_count) {
8367                                                 /* virtual generic call */
8368                                                 g_assert (mono_use_imt);
8369                                                 g_assert (!imt_arg);
8370                                                 /* Same as the virtual generic case above */
8371                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8372                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8373                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8374                                                 vtable_arg = NULL;
8375                                         }
8376                                 }
8377
8378                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8379                                         /* test_0_multi_dim_arrays () in gshared.cs */
8380                                         GSHAREDVT_FAILURE (*ip);
8381
8382                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8383                                         keep_this_alive = sp [0];
8384
8385                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8386                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8387                                 else
8388                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8389                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8390
8391                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8392                                 goto call_end;
8393                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8394                                 /*
8395                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8396                                  */
8397                                 MonoInst *callee = addr;
8398
8399                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8400                                         /* Not tested */
8401                                         GSHAREDVT_FAILURE (*ip);
8402
8403                                 addr = emit_get_rgctx_sig (cfg, context_used,
8404                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8405                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8406                                 goto call_end;
8407                         }
8408
8409                         /* Generic sharing */
8410                         /* FIXME: only do this for generic methods if
8411                            they are not shared! */
8412                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8413                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8414                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8415                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8416                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8417                                 INLINE_FAILURE ("gshared");
8418
8419                                 g_assert (cfg->generic_sharing_context && cmethod);
8420                                 g_assert (!addr);
8421
8422                                 /*
8423                                  * We are compiling a call to a
8424                                  * generic method from shared code,
8425                                  * which means that we have to look up
8426                                  * the method in the rgctx and do an
8427                                  * indirect call.
8428                                  */
8429                                 if (fsig->hasthis)
8430                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8431
8432                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8433                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8434                                 goto call_end;
8435                         }
8436
8437                         /* Indirect calls */
8438                         if (addr) {
8439                                 if (call_opcode == CEE_CALL)
8440                                         g_assert (context_used);
8441                                 else if (call_opcode == CEE_CALLI)
8442                                         g_assert (!vtable_arg);
8443                                 else
8444                                         /* FIXME: what the hell is this??? */
8445                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8446                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8447
8448                                 /* Prevent inlining of methods with indirect calls */
8449                                 INLINE_FAILURE ("indirect call");
8450
8451                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8452                                         int info_type;
8453                                         gpointer info_data;
8454
8455                                         /* 
8456                                          * Instead of emitting an indirect call, emit a direct call
8457                                          * with the contents of the aotconst as the patch info.
8458                                          */
8459                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8460                                                 info_type = addr->inst_c1;
8461                                                 info_data = addr->inst_p0;
8462                                         } else {
8463                                                 info_type = addr->inst_right->inst_c1;
8464                                                 info_data = addr->inst_right->inst_left;
8465                                         }
8466                                         
8467                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8468                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8469                                                 NULLIFY_INS (addr);
8470                                                 goto call_end;
8471                                         }
8472                                 }
8473                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8474                                 goto call_end;
8475                         }
8476                                         
8477                         /* Array methods */
8478                         if (array_rank) {
8479                                 MonoInst *addr;
8480
8481                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8482                                         MonoInst *val = sp [fsig->param_count];
8483
8484                                         if (val->type == STACK_OBJ) {
8485                                                 MonoInst *iargs [2];
8486
8487                                                 iargs [0] = sp [0];
8488                                                 iargs [1] = val;
8489                                                 
8490                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8491                                         }
8492                                         
8493                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8494                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8495                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8496                                                 emit_write_barrier (cfg, addr, val);
8497                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8498                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8499
8500                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8501                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8502                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8503                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8504                                         CHECK_TYPELOAD (cmethod->klass);
8505                                         
8506                                         readonly = FALSE;
8507                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8508                                         ins = addr;
8509                                 } else {
8510                                         g_assert_not_reached ();
8511                                 }
8512
8513                                 emit_widen = FALSE;
8514                                 goto call_end;
8515                         }
8516
8517                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8518                         if (ins)
8519                                 goto call_end;
8520
8521                         /* Tail prefix / tail call optimization */
8522
8523                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8524                         /* FIXME: runtime generic context pointer for jumps? */
8525                         /* FIXME: handle this for generic sharing eventually */
8526                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8527                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8528                                 supported_tail_call = TRUE;
8529
8530                         if (supported_tail_call) {
8531                                 MonoCallInst *call;
8532
8533                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8534                                 INLINE_FAILURE ("tail call");
8535
8536                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8537
8538                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8539                                         /* Handle tail calls similarly to normal calls */
8540                                         tail_call = TRUE;
8541                                 } else {
8542                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8543                                         call->tail_call = TRUE;
8544                                         call->method = cmethod;
8545                                         call->signature = mono_method_signature (cmethod);
8546
8547                                         /*
8548                                          * We implement tail calls by storing the actual arguments into the 
8549                                          * argument variables, then emitting a CEE_JMP.
8550                                          */
8551                                         for (i = 0; i < n; ++i) {
8552                                                 /* Prevent argument from being register allocated */
8553                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8554                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8555                                         }
8556                                         ins = (MonoInst*)call;
8557                                         ins->inst_p0 = cmethod;
8558                                         ins->inst_p1 = arg_array [0];
8559                                         MONO_ADD_INS (bblock, ins);
8560                                         link_bblock (cfg, bblock, end_bblock);                  
8561                                         start_new_bblock = 1;
8562
8563                                         // FIXME: Eliminate unreachable epilogs
8564
8565                                         /*
8566                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8567                                          * only reachable from this call.
8568                                          */
8569                                         GET_BBLOCK (cfg, tblock, ip + 5);
8570                                         if (tblock == bblock || tblock->in_count == 0)
8571                                                 skip_ret = TRUE;
8572                                         push_res = FALSE;
8573
8574                                         goto call_end;
8575                                 }
8576                         }
8577
8578                         /* 
8579                          * Synchronized wrappers.
8580                          * Its hard to determine where to replace a method with its synchronized
8581                          * wrapper without causing an infinite recursion. The current solution is
8582                          * to add the synchronized wrapper in the trampolines, and to
8583                          * change the called method to a dummy wrapper, and resolve that wrapper
8584                          * to the real method in mono_jit_compile_method ().
8585                          */
8586                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8587                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8588                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8589                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8590                         }
8591
8592                         /* Common call */
8593                         INLINE_FAILURE ("call");
8594                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8595                                                                                           imt_arg, vtable_arg);
8596
8597                         if (tail_call) {
8598                                 link_bblock (cfg, bblock, end_bblock);                  
8599                                 start_new_bblock = 1;
8600
8601                                 // FIXME: Eliminate unreachable epilogs
8602
8603                                 /*
8604                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8605                                  * only reachable from this call.
8606                                  */
8607                                 GET_BBLOCK (cfg, tblock, ip + 5);
8608                                 if (tblock == bblock || tblock->in_count == 0)
8609                                         skip_ret = TRUE;
8610                                 push_res = FALSE;
8611                         }
8612
8613                         call_end:
8614
8615                         /* End of call, INS should contain the result of the call, if any */
8616
8617                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8618                                 g_assert (ins);
8619                                 if (emit_widen)
8620                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8621                                 else
8622                                         *sp++ = ins;
8623                         }
8624
8625                         if (keep_this_alive) {
8626                                 MonoInst *dummy_use;
8627
8628                                 /* See mono_emit_method_call_full () */
8629                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8630                         }
8631
8632                         CHECK_CFG_EXCEPTION;
8633
8634                         ip += 5;
8635                         if (skip_ret) {
8636                                 g_assert (*ip == CEE_RET);
8637                                 ip += 1;
8638                         }
8639                         ins_flag = 0;
8640                         constrained_call = NULL;
8641                         if (need_seq_point)
8642                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8643                         break;
8644                 }
8645                 case CEE_RET:
8646                         if (cfg->method != method) {
8647                                 /* return from inlined method */
8648                                 /* 
8649                                  * If in_count == 0, that means the ret is unreachable due to
8650                                  * being preceeded by a throw. In that case, inline_method () will
8651                                  * handle setting the return value 
8652                                  * (test case: test_0_inline_throw ()).
8653                                  */
8654                                 if (return_var && cfg->cbb->in_count) {
8655                                         MonoType *ret_type = mono_method_signature (method)->ret;
8656
8657                                         MonoInst *store;
8658                                         CHECK_STACK (1);
8659                                         --sp;
8660
8661                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8662                                                 UNVERIFIED;
8663
8664                                         //g_assert (returnvar != -1);
8665                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8666                                         cfg->ret_var_set = TRUE;
8667                                 } 
8668                         } else {
8669                                 if (cfg->lmf_var && cfg->cbb->in_count)
8670                                         emit_pop_lmf (cfg);
8671
8672                                 if (cfg->ret) {
8673                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8674
8675                                         if (seq_points && !sym_seq_points) {
8676                                                 /* 
8677                                                  * Place a seq point here too even through the IL stack is not
8678                                                  * empty, so a step over on
8679                                                  * call <FOO>
8680                                                  * ret
8681                                                  * will work correctly.
8682                                                  */
8683                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8684                                                 MONO_ADD_INS (cfg->cbb, ins);
8685                                         }
8686
8687                                         g_assert (!return_var);
8688                                         CHECK_STACK (1);
8689                                         --sp;
8690
8691                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8692                                                 UNVERIFIED;
8693
8694                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8695                                                 MonoInst *ret_addr;
8696
8697                                                 if (!cfg->vret_addr) {
8698                                                         MonoInst *ins;
8699
8700                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8701                                                 } else {
8702                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8703
8704                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8705                                                         ins->klass = mono_class_from_mono_type (ret_type);
8706                                                 }
8707                                         } else {
8708 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8709                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8710                                                         MonoInst *iargs [1];
8711                                                         MonoInst *conv;
8712
8713                                                         iargs [0] = *sp;
8714                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8715                                                         mono_arch_emit_setret (cfg, method, conv);
8716                                                 } else {
8717                                                         mono_arch_emit_setret (cfg, method, *sp);
8718                                                 }
8719 #else
8720                                                 mono_arch_emit_setret (cfg, method, *sp);
8721 #endif
8722                                         }
8723                                 }
8724                         }
8725                         if (sp != stack_start)
8726                                 UNVERIFIED;
8727                         MONO_INST_NEW (cfg, ins, OP_BR);
8728                         ip++;
8729                         ins->inst_target_bb = end_bblock;
8730                         MONO_ADD_INS (bblock, ins);
8731                         link_bblock (cfg, bblock, end_bblock);
8732                         start_new_bblock = 1;
8733                         break;
8734                 case CEE_BR_S:
8735                         CHECK_OPSIZE (2);
8736                         MONO_INST_NEW (cfg, ins, OP_BR);
8737                         ip++;
8738                         target = ip + 1 + (signed char)(*ip);
8739                         ++ip;
8740                         GET_BBLOCK (cfg, tblock, target);
8741                         link_bblock (cfg, bblock, tblock);
8742                         ins->inst_target_bb = tblock;
8743                         if (sp != stack_start) {
8744                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8745                                 sp = stack_start;
8746                                 CHECK_UNVERIFIABLE (cfg);
8747                         }
8748                         MONO_ADD_INS (bblock, ins);
8749                         start_new_bblock = 1;
8750                         inline_costs += BRANCH_COST;
8751                         break;
8752                 case CEE_BEQ_S:
8753                 case CEE_BGE_S:
8754                 case CEE_BGT_S:
8755                 case CEE_BLE_S:
8756                 case CEE_BLT_S:
8757                 case CEE_BNE_UN_S:
8758                 case CEE_BGE_UN_S:
8759                 case CEE_BGT_UN_S:
8760                 case CEE_BLE_UN_S:
8761                 case CEE_BLT_UN_S:
8762                         CHECK_OPSIZE (2);
8763                         CHECK_STACK (2);
8764                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8765                         ip++;
8766                         target = ip + 1 + *(signed char*)ip;
8767                         ip++;
8768
8769                         ADD_BINCOND (NULL);
8770
8771                         sp = stack_start;
8772                         inline_costs += BRANCH_COST;
8773                         break;
8774                 case CEE_BR:
8775                         CHECK_OPSIZE (5);
8776                         MONO_INST_NEW (cfg, ins, OP_BR);
8777                         ip++;
8778
8779                         target = ip + 4 + (gint32)read32(ip);
8780                         ip += 4;
8781                         GET_BBLOCK (cfg, tblock, target);
8782                         link_bblock (cfg, bblock, tblock);
8783                         ins->inst_target_bb = tblock;
8784                         if (sp != stack_start) {
8785                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8786                                 sp = stack_start;
8787                                 CHECK_UNVERIFIABLE (cfg);
8788                         }
8789
8790                         MONO_ADD_INS (bblock, ins);
8791
8792                         start_new_bblock = 1;
8793                         inline_costs += BRANCH_COST;
8794                         break;
8795                 case CEE_BRFALSE_S:
8796                 case CEE_BRTRUE_S:
8797                 case CEE_BRFALSE:
8798                 case CEE_BRTRUE: {
8799                         MonoInst *cmp;
8800                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8801                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8802                         guint32 opsize = is_short ? 1 : 4;
8803
8804                         CHECK_OPSIZE (opsize);
8805                         CHECK_STACK (1);
8806                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8807                                 UNVERIFIED;
8808                         ip ++;
8809                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8810                         ip += opsize;
8811
8812                         sp--;
8813
8814                         GET_BBLOCK (cfg, tblock, target);
8815                         link_bblock (cfg, bblock, tblock);
8816                         GET_BBLOCK (cfg, tblock, ip);
8817                         link_bblock (cfg, bblock, tblock);
8818
8819                         if (sp != stack_start) {
8820                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8821                                 CHECK_UNVERIFIABLE (cfg);
8822                         }
8823
8824                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8825                         cmp->sreg1 = sp [0]->dreg;
8826                         type_from_op (cmp, sp [0], NULL);
8827                         CHECK_TYPE (cmp);
8828
8829 #if SIZEOF_REGISTER == 4
8830                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8831                                 /* Convert it to OP_LCOMPARE */
8832                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8833                                 ins->type = STACK_I8;
8834                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8835                                 ins->inst_l = 0;
8836                                 MONO_ADD_INS (bblock, ins);
8837                                 cmp->opcode = OP_LCOMPARE;
8838                                 cmp->sreg2 = ins->dreg;
8839                         }
8840 #endif
8841                         MONO_ADD_INS (bblock, cmp);
8842
8843                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8844                         type_from_op (ins, sp [0], NULL);
8845                         MONO_ADD_INS (bblock, ins);
8846                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8847                         GET_BBLOCK (cfg, tblock, target);
8848                         ins->inst_true_bb = tblock;
8849                         GET_BBLOCK (cfg, tblock, ip);
8850                         ins->inst_false_bb = tblock;
8851                         start_new_bblock = 2;
8852
8853                         sp = stack_start;
8854                         inline_costs += BRANCH_COST;
8855                         break;
8856                 }
8857                 case CEE_BEQ:
8858                 case CEE_BGE:
8859                 case CEE_BGT:
8860                 case CEE_BLE:
8861                 case CEE_BLT:
8862                 case CEE_BNE_UN:
8863                 case CEE_BGE_UN:
8864                 case CEE_BGT_UN:
8865                 case CEE_BLE_UN:
8866                 case CEE_BLT_UN:
8867                         CHECK_OPSIZE (5);
8868                         CHECK_STACK (2);
8869                         MONO_INST_NEW (cfg, ins, *ip);
8870                         ip++;
8871                         target = ip + 4 + (gint32)read32(ip);
8872                         ip += 4;
8873
8874                         ADD_BINCOND (NULL);
8875
8876                         sp = stack_start;
8877                         inline_costs += BRANCH_COST;
8878                         break;
8879                 case CEE_SWITCH: {
8880                         MonoInst *src1;
8881                         MonoBasicBlock **targets;
8882                         MonoBasicBlock *default_bblock;
8883                         MonoJumpInfoBBTable *table;
8884                         int offset_reg = alloc_preg (cfg);
8885                         int target_reg = alloc_preg (cfg);
8886                         int table_reg = alloc_preg (cfg);
8887                         int sum_reg = alloc_preg (cfg);
8888                         gboolean use_op_switch;
8889
8890                         CHECK_OPSIZE (5);
8891                         CHECK_STACK (1);
8892                         n = read32 (ip + 1);
8893                         --sp;
8894                         src1 = sp [0];
8895                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8896                                 UNVERIFIED;
8897
8898                         ip += 5;
8899                         CHECK_OPSIZE (n * sizeof (guint32));
8900                         target = ip + n * sizeof (guint32);
8901
8902                         GET_BBLOCK (cfg, default_bblock, target);
8903                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8904
8905                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8906                         for (i = 0; i < n; ++i) {
8907                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8908                                 targets [i] = tblock;
8909                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8910                                 ip += 4;
8911                         }
8912
8913                         if (sp != stack_start) {
8914                                 /* 
8915                                  * Link the current bb with the targets as well, so handle_stack_args
8916                                  * will set their in_stack correctly.
8917                                  */
8918                                 link_bblock (cfg, bblock, default_bblock);
8919                                 for (i = 0; i < n; ++i)
8920                                         link_bblock (cfg, bblock, targets [i]);
8921
8922                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8923                                 sp = stack_start;
8924                                 CHECK_UNVERIFIABLE (cfg);
8925                         }
8926
8927                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8928                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8929                         bblock = cfg->cbb;
8930
8931                         for (i = 0; i < n; ++i)
8932                                 link_bblock (cfg, bblock, targets [i]);
8933
8934                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8935                         table->table = targets;
8936                         table->table_size = n;
8937
8938                         use_op_switch = FALSE;
8939 #ifdef TARGET_ARM
8940                         /* ARM implements SWITCH statements differently */
8941                         /* FIXME: Make it use the generic implementation */
8942                         if (!cfg->compile_aot)
8943                                 use_op_switch = TRUE;
8944 #endif
8945
8946                         if (COMPILE_LLVM (cfg))
8947                                 use_op_switch = TRUE;
8948
8949                         cfg->cbb->has_jump_table = 1;
8950
8951                         if (use_op_switch) {
8952                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8953                                 ins->sreg1 = src1->dreg;
8954                                 ins->inst_p0 = table;
8955                                 ins->inst_many_bb = targets;
8956                                 ins->klass = GUINT_TO_POINTER (n);
8957                                 MONO_ADD_INS (cfg->cbb, ins);
8958                         } else {
8959                                 if (sizeof (gpointer) == 8)
8960                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8961                                 else
8962                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8963
8964 #if SIZEOF_REGISTER == 8
8965                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8966                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8967 #endif
8968
8969                                 if (cfg->compile_aot) {
8970                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8971                                 } else {
8972                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8973                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8974                                         ins->inst_p0 = table;
8975                                         ins->dreg = table_reg;
8976                                         MONO_ADD_INS (cfg->cbb, ins);
8977                                 }
8978
8979                                 /* FIXME: Use load_memindex */
8980                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8981                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8982                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8983                         }
8984                         start_new_bblock = 1;
8985                         inline_costs += (BRANCH_COST * 2);
8986                         break;
8987                 }
8988                 case CEE_LDIND_I1:
8989                 case CEE_LDIND_U1:
8990                 case CEE_LDIND_I2:
8991                 case CEE_LDIND_U2:
8992                 case CEE_LDIND_I4:
8993                 case CEE_LDIND_U4:
8994                 case CEE_LDIND_I8:
8995                 case CEE_LDIND_I:
8996                 case CEE_LDIND_R4:
8997                 case CEE_LDIND_R8:
8998                 case CEE_LDIND_REF:
8999                         CHECK_STACK (1);
9000                         --sp;
9001
9002                         switch (*ip) {
9003                         case CEE_LDIND_R4:
9004                         case CEE_LDIND_R8:
9005                                 dreg = alloc_freg (cfg);
9006                                 break;
9007                         case CEE_LDIND_I8:
9008                                 dreg = alloc_lreg (cfg);
9009                                 break;
9010                         case CEE_LDIND_REF:
9011                                 dreg = alloc_ireg_ref (cfg);
9012                                 break;
9013                         default:
9014                                 dreg = alloc_preg (cfg);
9015                         }
9016
9017                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9018                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9019                         ins->flags |= ins_flag;
9020                         MONO_ADD_INS (bblock, ins);
9021                         *sp++ = ins;
9022                         if (ins_flag & MONO_INST_VOLATILE) {
9023                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9024                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9025                                 emit_memory_barrier (cfg, FullBarrier);
9026                         }
9027                         ins_flag = 0;
9028                         ++ip;
9029                         break;
9030                 case CEE_STIND_REF:
9031                 case CEE_STIND_I1:
9032                 case CEE_STIND_I2:
9033                 case CEE_STIND_I4:
9034                 case CEE_STIND_I8:
9035                 case CEE_STIND_R4:
9036                 case CEE_STIND_R8:
9037                 case CEE_STIND_I:
9038                         CHECK_STACK (2);
9039                         sp -= 2;
9040
9041                         if (ins_flag & MONO_INST_VOLATILE) {
9042                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9043                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9044                                 emit_memory_barrier (cfg, FullBarrier);
9045                         }
9046
9047                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9048                         ins->flags |= ins_flag;
9049                         ins_flag = 0;
9050
9051                         MONO_ADD_INS (bblock, ins);
9052
9053                         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)))
9054                                 emit_write_barrier (cfg, sp [0], sp [1]);
9055
9056                         inline_costs += 1;
9057                         ++ip;
9058                         break;
9059
9060                 case CEE_MUL:
9061                         CHECK_STACK (2);
9062
9063                         MONO_INST_NEW (cfg, ins, (*ip));
9064                         sp -= 2;
9065                         ins->sreg1 = sp [0]->dreg;
9066                         ins->sreg2 = sp [1]->dreg;
9067                         type_from_op (ins, sp [0], sp [1]);
9068                         CHECK_TYPE (ins);
9069                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9070
9071                         /* Use the immediate opcodes if possible */
9072                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9073                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9074                                 if (imm_opcode != -1) {
9075                                         ins->opcode = imm_opcode;
9076                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9077                                         ins->sreg2 = -1;
9078
9079                                         sp [1]->opcode = OP_NOP;
9080                                 }
9081                         }
9082
9083                         MONO_ADD_INS ((cfg)->cbb, (ins));
9084
9085                         *sp++ = mono_decompose_opcode (cfg, ins);
9086                         ip++;
9087                         break;
9088                 case CEE_ADD:
9089                 case CEE_SUB:
9090                 case CEE_DIV:
9091                 case CEE_DIV_UN:
9092                 case CEE_REM:
9093                 case CEE_REM_UN:
9094                 case CEE_AND:
9095                 case CEE_OR:
9096                 case CEE_XOR:
9097                 case CEE_SHL:
9098                 case CEE_SHR:
9099                 case CEE_SHR_UN:
9100                         CHECK_STACK (2);
9101
9102                         MONO_INST_NEW (cfg, ins, (*ip));
9103                         sp -= 2;
9104                         ins->sreg1 = sp [0]->dreg;
9105                         ins->sreg2 = sp [1]->dreg;
9106                         type_from_op (ins, sp [0], sp [1]);
9107                         CHECK_TYPE (ins);
9108                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9109                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9110
9111                         /* FIXME: Pass opcode to is_inst_imm */
9112
9113                         /* Use the immediate opcodes if possible */
9114                         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)) {
9115                                 int imm_opcode;
9116
9117                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9118 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9119                                 /* Keep emulated opcodes which are optimized away later */
9120                                 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) {
9121                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9122                                 }
9123 #endif
9124                                 if (imm_opcode != -1) {
9125                                         ins->opcode = imm_opcode;
9126                                         if (sp [1]->opcode == OP_I8CONST) {
9127 #if SIZEOF_REGISTER == 8
9128                                                 ins->inst_imm = sp [1]->inst_l;
9129 #else
9130                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9131                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9132 #endif
9133                                         }
9134                                         else
9135                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9136                                         ins->sreg2 = -1;
9137
9138                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9139                                         if (sp [1]->next == NULL)
9140                                                 sp [1]->opcode = OP_NOP;
9141                                 }
9142                         }
9143                         MONO_ADD_INS ((cfg)->cbb, (ins));
9144
9145                         *sp++ = mono_decompose_opcode (cfg, ins);
9146                         ip++;
9147                         break;
9148                 case CEE_NEG:
9149                 case CEE_NOT:
9150                 case CEE_CONV_I1:
9151                 case CEE_CONV_I2:
9152                 case CEE_CONV_I4:
9153                 case CEE_CONV_R4:
9154                 case CEE_CONV_R8:
9155                 case CEE_CONV_U4:
9156                 case CEE_CONV_I8:
9157                 case CEE_CONV_U8:
9158                 case CEE_CONV_OVF_I8:
9159                 case CEE_CONV_OVF_U8:
9160                 case CEE_CONV_R_UN:
9161                         CHECK_STACK (1);
9162
9163                         /* Special case this earlier so we have long constants in the IR */
9164                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9165                                 int data = sp [-1]->inst_c0;
9166                                 sp [-1]->opcode = OP_I8CONST;
9167                                 sp [-1]->type = STACK_I8;
9168 #if SIZEOF_REGISTER == 8
9169                                 if ((*ip) == CEE_CONV_U8)
9170                                         sp [-1]->inst_c0 = (guint32)data;
9171                                 else
9172                                         sp [-1]->inst_c0 = data;
9173 #else
9174                                 sp [-1]->inst_ls_word = data;
9175                                 if ((*ip) == CEE_CONV_U8)
9176                                         sp [-1]->inst_ms_word = 0;
9177                                 else
9178                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9179 #endif
9180                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9181                         }
9182                         else {
9183                                 ADD_UNOP (*ip);
9184                         }
9185                         ip++;
9186                         break;
9187                 case CEE_CONV_OVF_I4:
9188                 case CEE_CONV_OVF_I1:
9189                 case CEE_CONV_OVF_I2:
9190                 case CEE_CONV_OVF_I:
9191                 case CEE_CONV_OVF_U:
9192                         CHECK_STACK (1);
9193
9194                         if (sp [-1]->type == STACK_R8) {
9195                                 ADD_UNOP (CEE_CONV_OVF_I8);
9196                                 ADD_UNOP (*ip);
9197                         } else {
9198                                 ADD_UNOP (*ip);
9199                         }
9200                         ip++;
9201                         break;
9202                 case CEE_CONV_OVF_U1:
9203                 case CEE_CONV_OVF_U2:
9204                 case CEE_CONV_OVF_U4:
9205                         CHECK_STACK (1);
9206
9207                         if (sp [-1]->type == STACK_R8) {
9208                                 ADD_UNOP (CEE_CONV_OVF_U8);
9209                                 ADD_UNOP (*ip);
9210                         } else {
9211                                 ADD_UNOP (*ip);
9212                         }
9213                         ip++;
9214                         break;
9215                 case CEE_CONV_OVF_I1_UN:
9216                 case CEE_CONV_OVF_I2_UN:
9217                 case CEE_CONV_OVF_I4_UN:
9218                 case CEE_CONV_OVF_I8_UN:
9219                 case CEE_CONV_OVF_U1_UN:
9220                 case CEE_CONV_OVF_U2_UN:
9221                 case CEE_CONV_OVF_U4_UN:
9222                 case CEE_CONV_OVF_U8_UN:
9223                 case CEE_CONV_OVF_I_UN:
9224                 case CEE_CONV_OVF_U_UN:
9225                 case CEE_CONV_U2:
9226                 case CEE_CONV_U1:
9227                 case CEE_CONV_I:
9228                 case CEE_CONV_U:
9229                         CHECK_STACK (1);
9230                         ADD_UNOP (*ip);
9231                         CHECK_CFG_EXCEPTION;
9232                         ip++;
9233                         break;
9234                 case CEE_ADD_OVF:
9235                 case CEE_ADD_OVF_UN:
9236                 case CEE_MUL_OVF:
9237                 case CEE_MUL_OVF_UN:
9238                 case CEE_SUB_OVF:
9239                 case CEE_SUB_OVF_UN:
9240                         CHECK_STACK (2);
9241                         ADD_BINOP (*ip);
9242                         ip++;
9243                         break;
9244                 case CEE_CPOBJ:
9245                         GSHAREDVT_FAILURE (*ip);
9246                         CHECK_OPSIZE (5);
9247                         CHECK_STACK (2);
9248                         token = read32 (ip + 1);
9249                         klass = mini_get_class (method, token, generic_context);
9250                         CHECK_TYPELOAD (klass);
9251                         sp -= 2;
9252                         if (generic_class_is_reference_type (cfg, klass)) {
9253                                 MonoInst *store, *load;
9254                                 int dreg = alloc_ireg_ref (cfg);
9255
9256                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9257                                 load->flags |= ins_flag;
9258                                 MONO_ADD_INS (cfg->cbb, load);
9259
9260                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9261                                 store->flags |= ins_flag;
9262                                 MONO_ADD_INS (cfg->cbb, store);
9263
9264                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9265                                         emit_write_barrier (cfg, sp [0], sp [1]);
9266                         } else {
9267                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9268                         }
9269                         ins_flag = 0;
9270                         ip += 5;
9271                         break;
9272                 case CEE_LDOBJ: {
9273                         int loc_index = -1;
9274                         int stloc_len = 0;
9275
9276                         CHECK_OPSIZE (5);
9277                         CHECK_STACK (1);
9278                         --sp;
9279                         token = read32 (ip + 1);
9280                         klass = mini_get_class (method, token, generic_context);
9281                         CHECK_TYPELOAD (klass);
9282
9283                         /* Optimize the common ldobj+stloc combination */
9284                         switch (ip [5]) {
9285                         case CEE_STLOC_S:
9286                                 loc_index = ip [6];
9287                                 stloc_len = 2;
9288                                 break;
9289                         case CEE_STLOC_0:
9290                         case CEE_STLOC_1:
9291                         case CEE_STLOC_2:
9292                         case CEE_STLOC_3:
9293                                 loc_index = ip [5] - CEE_STLOC_0;
9294                                 stloc_len = 1;
9295                                 break;
9296                         default:
9297                                 break;
9298                         }
9299
9300                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9301                                 CHECK_LOCAL (loc_index);
9302
9303                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9304                                 ins->dreg = cfg->locals [loc_index]->dreg;
9305                                 ins->flags |= ins_flag;
9306                                 ip += 5;
9307                                 ip += stloc_len;
9308                                 if (ins_flag & MONO_INST_VOLATILE) {
9309                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9310                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9311                                         emit_memory_barrier (cfg, FullBarrier);
9312                                 }
9313                                 ins_flag = 0;
9314                                 break;
9315                         }
9316
9317                         /* Optimize the ldobj+stobj combination */
9318                         /* The reference case ends up being a load+store anyway */
9319                         /* Skip this if the operation is volatile. */
9320                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
9321                                 CHECK_STACK (1);
9322
9323                                 sp --;
9324
9325                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9326
9327                                 ip += 5 + 5;
9328                                 ins_flag = 0;
9329                                 break;
9330                         }
9331
9332                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9333                         ins->flags |= ins_flag;
9334                         *sp++ = ins;
9335
9336                         if (ins_flag & MONO_INST_VOLATILE) {
9337                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9338                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9339                                 emit_memory_barrier (cfg, FullBarrier);
9340                         }
9341
9342                         ip += 5;
9343                         ins_flag = 0;
9344                         inline_costs += 1;
9345                         break;
9346                 }
9347                 case CEE_LDSTR:
9348                         CHECK_STACK_OVF (1);
9349                         CHECK_OPSIZE (5);
9350                         n = read32 (ip + 1);
9351
9352                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9353                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9354                                 ins->type = STACK_OBJ;
9355                                 *sp = ins;
9356                         }
9357                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9358                                 MonoInst *iargs [1];
9359
9360                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9361                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9362                         } else {
9363                                 if (cfg->opt & MONO_OPT_SHARED) {
9364                                         MonoInst *iargs [3];
9365
9366                                         if (cfg->compile_aot) {
9367                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9368                                         }
9369                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9370                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9371                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9372                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9373                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9374                                 } else {
9375                                         if (bblock->out_of_line) {
9376                                                 MonoInst *iargs [2];
9377
9378                                                 if (image == mono_defaults.corlib) {
9379                                                         /* 
9380                                                          * Avoid relocations in AOT and save some space by using a 
9381                                                          * version of helper_ldstr specialized to mscorlib.
9382                                                          */
9383                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9384                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9385                                                 } else {
9386                                                         /* Avoid creating the string object */
9387                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9388                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9389                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9390                                                 }
9391                                         } 
9392                                         else
9393                                         if (cfg->compile_aot) {
9394                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9395                                                 *sp = ins;
9396                                                 MONO_ADD_INS (bblock, ins);
9397                                         } 
9398                                         else {
9399                                                 NEW_PCONST (cfg, ins, NULL);
9400                                                 ins->type = STACK_OBJ;
9401                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9402                                                 if (!ins->inst_p0)
9403                                                         OUT_OF_MEMORY_FAILURE;
9404
9405                                                 *sp = ins;
9406                                                 MONO_ADD_INS (bblock, ins);
9407                                         }
9408                                 }
9409                         }
9410
9411                         sp++;
9412                         ip += 5;
9413                         break;
9414                 case CEE_NEWOBJ: {
9415                         MonoInst *iargs [2];
9416                         MonoMethodSignature *fsig;
9417                         MonoInst this_ins;
9418                         MonoInst *alloc;
9419                         MonoInst *vtable_arg = NULL;
9420
9421                         CHECK_OPSIZE (5);
9422                         token = read32 (ip + 1);
9423                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9424                         if (!cmethod || mono_loader_get_last_error ())
9425                                 LOAD_ERROR;
9426                         fsig = mono_method_get_signature (cmethod, image, token);
9427                         if (!fsig)
9428                                 LOAD_ERROR;
9429
9430                         mono_save_token_info (cfg, image, token, cmethod);
9431
9432                         if (!mono_class_init (cmethod->klass))
9433                                 TYPE_LOAD_ERROR (cmethod->klass);
9434
9435                         context_used = mini_method_check_context_used (cfg, cmethod);
9436
9437                         if (mono_security_cas_enabled ()) {
9438                                 if (check_linkdemand (cfg, method, cmethod))
9439                                         INLINE_FAILURE ("linkdemand");
9440                                 CHECK_CFG_EXCEPTION;
9441                         } else if (mono_security_core_clr_enabled ()) {
9442                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9443                         }
9444
9445                         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)) {
9446                                 emit_generic_class_init (cfg, cmethod->klass);
9447                                 CHECK_TYPELOAD (cmethod->klass);
9448                         }
9449
9450                         /*
9451                         if (cfg->gsharedvt) {
9452                                 if (mini_is_gsharedvt_variable_signature (sig))
9453                                         GSHAREDVT_FAILURE (*ip);
9454                         }
9455                         */
9456
9457                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9458                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9459                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9460                                         mono_class_vtable (cfg->domain, cmethod->klass);
9461                                         CHECK_TYPELOAD (cmethod->klass);
9462
9463                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9464                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9465                                 } else {
9466                                         if (context_used) {
9467                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9468                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9469                                         } else {
9470                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9471
9472                                                 CHECK_TYPELOAD (cmethod->klass);
9473                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9474                                         }
9475                                 }
9476                         }
9477
9478                         n = fsig->param_count;
9479                         CHECK_STACK (n);
9480
9481                         /* 
9482                          * Generate smaller code for the common newobj <exception> instruction in
9483                          * argument checking code.
9484                          */
9485                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9486                                 is_exception_class (cmethod->klass) && n <= 2 &&
9487                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9488                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9489                                 MonoInst *iargs [3];
9490
9491                                 g_assert (!vtable_arg);
9492
9493                                 sp -= n;
9494
9495                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9496                                 switch (n) {
9497                                 case 0:
9498                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9499                                         break;
9500                                 case 1:
9501                                         iargs [1] = sp [0];
9502                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9503                                         break;
9504                                 case 2:
9505                                         iargs [1] = sp [0];
9506                                         iargs [2] = sp [1];
9507                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9508                                         break;
9509                                 default:
9510                                         g_assert_not_reached ();
9511                                 }
9512
9513                                 ip += 5;
9514                                 inline_costs += 5;
9515                                 break;
9516                         }
9517
9518                         /* move the args to allow room for 'this' in the first position */
9519                         while (n--) {
9520                                 --sp;
9521                                 sp [1] = sp [0];
9522                         }
9523
9524                         /* check_call_signature () requires sp[0] to be set */
9525                         this_ins.type = STACK_OBJ;
9526                         sp [0] = &this_ins;
9527                         if (check_call_signature (cfg, fsig, sp))
9528                                 UNVERIFIED;
9529
9530                         iargs [0] = NULL;
9531
9532                         if (mini_class_is_system_array (cmethod->klass)) {
9533                                 g_assert (!vtable_arg);
9534
9535                                 *sp = emit_get_rgctx_method (cfg, context_used,
9536                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9537
9538                                 /* Avoid varargs in the common case */
9539                                 if (fsig->param_count == 1)
9540                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9541                                 else if (fsig->param_count == 2)
9542                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9543                                 else if (fsig->param_count == 3)
9544                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9545                                 else if (fsig->param_count == 4)
9546                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9547                                 else
9548                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9549                         } else if (cmethod->string_ctor) {
9550                                 g_assert (!context_used);
9551                                 g_assert (!vtable_arg);
9552                                 /* we simply pass a null pointer */
9553                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9554                                 /* now call the string ctor */
9555                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9556                         } else {
9557                                 MonoInst* callvirt_this_arg = NULL;
9558                                 
9559                                 if (cmethod->klass->valuetype) {
9560                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9561                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9562                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9563
9564                                         alloc = NULL;
9565
9566                                         /* 
9567                                          * The code generated by mini_emit_virtual_call () expects
9568                                          * iargs [0] to be a boxed instance, but luckily the vcall
9569                                          * will be transformed into a normal call there.
9570                                          */
9571                                 } else if (context_used) {
9572                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9573                                         *sp = alloc;
9574                                 } else {
9575                                         MonoVTable *vtable = NULL;
9576
9577                                         if (!cfg->compile_aot)
9578                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9579                                         CHECK_TYPELOAD (cmethod->klass);
9580
9581                                         /*
9582                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9583                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9584                                          * As a workaround, we call class cctors before allocating objects.
9585                                          */
9586                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9587                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9588                                                 if (cfg->verbose_level > 2)
9589                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9590                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9591                                         }
9592
9593                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9594                                         *sp = alloc;
9595                                 }
9596                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9597
9598                                 if (alloc)
9599                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9600
9601                                 /* Now call the actual ctor */
9602                                 /* Avoid virtual calls to ctors if possible */
9603                                 if (mono_class_is_marshalbyref (cmethod->klass))
9604                                         callvirt_this_arg = sp [0];
9605
9606
9607                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9608                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9609                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9610                                                 *sp = ins;
9611                                                 sp++;
9612                                         }
9613
9614                                         CHECK_CFG_EXCEPTION;
9615                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9616                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9617                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9618                                     !g_list_find (dont_inline, cmethod)) {
9619                                         int costs;
9620
9621                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9622                                                 cfg->real_offset += 5;
9623                                                 bblock = cfg->cbb;
9624
9625                                                 inline_costs += costs - 5;
9626                                         } else {
9627                                                 INLINE_FAILURE ("inline failure");
9628                                                 // FIXME-VT: Clean this up
9629                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9630                                                         GSHAREDVT_FAILURE(*ip);
9631                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9632                                         }
9633                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9634                                         MonoInst *addr;
9635
9636                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9637                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9638                                 } else if (context_used &&
9639                                                    ((!mono_method_is_generic_sharable (cmethod, TRUE) ||
9640                                                          !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
9641                                         MonoInst *cmethod_addr;
9642
9643                                         /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
9644
9645                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9646                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9647
9648                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9649                                 } else {
9650                                         INLINE_FAILURE ("ctor call");
9651                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9652                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9653                                 }
9654                         }
9655
9656                         if (alloc == NULL) {
9657                                 /* Valuetype */
9658                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9659                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9660                                 *sp++= ins;
9661                         }
9662                         else
9663                                 *sp++ = alloc;
9664                         
9665                         ip += 5;
9666                         inline_costs += 5;
9667                         break;
9668                 }
9669                 case CEE_CASTCLASS:
9670                         CHECK_STACK (1);
9671                         --sp;
9672                         CHECK_OPSIZE (5);
9673                         token = read32 (ip + 1);
9674                         klass = mini_get_class (method, token, generic_context);
9675                         CHECK_TYPELOAD (klass);
9676                         if (sp [0]->type != STACK_OBJ)
9677                                 UNVERIFIED;
9678
9679                         context_used = mini_class_check_context_used (cfg, klass);
9680
9681                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9682                                 MonoInst *args [3];
9683
9684                                 /* obj */
9685                                 args [0] = *sp;
9686
9687                                 /* klass */
9688                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9689
9690                                 /* inline cache*/
9691                                 if (cfg->compile_aot)
9692                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9693                                 else
9694                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9695
9696                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9697
9698                                 *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9699                                 ip += 5;
9700                                 inline_costs += 2;
9701                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9702                                 MonoMethod *mono_castclass;
9703                                 MonoInst *iargs [1];
9704                                 int costs;
9705
9706                                 mono_castclass = mono_marshal_get_castclass (klass); 
9707                                 iargs [0] = sp [0];
9708                                 
9709                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9710                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9711                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9712                                 reset_cast_details (cfg);
9713                                 CHECK_CFG_EXCEPTION;
9714                                 g_assert (costs > 0);
9715                                 
9716                                 ip += 5;
9717                                 cfg->real_offset += 5;
9718                                 bblock = cfg->cbb;
9719
9720                                 *sp++ = iargs [0];
9721
9722                                 inline_costs += costs;
9723                         }
9724                         else {
9725                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9726                                 CHECK_CFG_EXCEPTION;
9727                                 bblock = cfg->cbb;
9728                                 *sp ++ = ins;
9729                                 ip += 5;
9730                         }
9731                         break;
9732                 case CEE_ISINST: {
9733                         CHECK_STACK (1);
9734                         --sp;
9735                         CHECK_OPSIZE (5);
9736                         token = read32 (ip + 1);
9737                         klass = mini_get_class (method, token, generic_context);
9738                         CHECK_TYPELOAD (klass);
9739                         if (sp [0]->type != STACK_OBJ)
9740                                 UNVERIFIED;
9741  
9742                         context_used = mini_class_check_context_used (cfg, klass);
9743
9744                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9745                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9746                                 MonoInst *args [3];
9747
9748                                 /* obj */
9749                                 args [0] = *sp;
9750
9751                                 /* klass */
9752                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9753
9754                                 /* inline cache*/
9755                                 if (cfg->compile_aot)
9756                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9757                                 else
9758                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9759
9760                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9761                                 ip += 5;
9762                                 inline_costs += 2;
9763                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9764                                 MonoMethod *mono_isinst;
9765                                 MonoInst *iargs [1];
9766                                 int costs;
9767
9768                                 mono_isinst = mono_marshal_get_isinst (klass); 
9769                                 iargs [0] = sp [0];
9770
9771                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9772                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9773                                 CHECK_CFG_EXCEPTION;
9774                                 g_assert (costs > 0);
9775                                 
9776                                 ip += 5;
9777                                 cfg->real_offset += 5;
9778                                 bblock = cfg->cbb;
9779
9780                                 *sp++= iargs [0];
9781
9782                                 inline_costs += costs;
9783                         }
9784                         else {
9785                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9786                                 CHECK_CFG_EXCEPTION;
9787                                 bblock = cfg->cbb;
9788                                 *sp ++ = ins;
9789                                 ip += 5;
9790                         }
9791                         break;
9792                 }
9793                 case CEE_UNBOX_ANY: {
9794                         CHECK_STACK (1);
9795                         --sp;
9796                         CHECK_OPSIZE (5);
9797                         token = read32 (ip + 1);
9798                         klass = mini_get_class (method, token, generic_context);
9799                         CHECK_TYPELOAD (klass);
9800  
9801                         mono_save_token_info (cfg, image, token, klass);
9802
9803                         context_used = mini_class_check_context_used (cfg, klass);
9804
9805                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9806                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9807                                 sp ++;
9808
9809                                 ip += 5;
9810                                 inline_costs += 2;
9811                                 break;
9812                         }
9813
9814                         if (generic_class_is_reference_type (cfg, klass)) {
9815                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9816                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9817                                         MonoInst *args [3];
9818
9819                                         /* obj */
9820                                         args [0] = *sp;
9821
9822                                         /* klass */
9823                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9824
9825                                         /* inline cache*/
9826                                         /*FIXME AOT support*/
9827                                         if (cfg->compile_aot)
9828                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9829                                         else
9830                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9831
9832                                         /* The wrapper doesn't inline well so the bloat of inlining doesn't pay off. */
9833                                         *sp++ = emit_castclass_with_cache (cfg, klass, args, &bblock);
9834                                         ip += 5;
9835                                         inline_costs += 2;
9836                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9837                                         MonoMethod *mono_castclass;
9838                                         MonoInst *iargs [1];
9839                                         int costs;
9840
9841                                         mono_castclass = mono_marshal_get_castclass (klass); 
9842                                         iargs [0] = sp [0];
9843
9844                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9845                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9846                                         CHECK_CFG_EXCEPTION;
9847                                         g_assert (costs > 0);
9848                                 
9849                                         ip += 5;
9850                                         cfg->real_offset += 5;
9851                                         bblock = cfg->cbb;
9852
9853                                         *sp++ = iargs [0];
9854                                         inline_costs += costs;
9855                                 } else {
9856                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9857                                         CHECK_CFG_EXCEPTION;
9858                                         bblock = cfg->cbb;
9859                                         *sp ++ = ins;
9860                                         ip += 5;
9861                                 }
9862                                 break;
9863                         }
9864
9865                         if (mono_class_is_nullable (klass)) {
9866                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9867                                 *sp++= ins;
9868                                 ip += 5;
9869                                 break;
9870                         }
9871
9872                         /* UNBOX */
9873                         ins = handle_unbox (cfg, klass, sp, context_used);
9874                         *sp = ins;
9875
9876                         ip += 5;
9877
9878                         /* LDOBJ */
9879                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9880                         *sp++ = ins;
9881
9882                         inline_costs += 2;
9883                         break;
9884                 }
9885                 case CEE_BOX: {
9886                         MonoInst *val;
9887
9888                         CHECK_STACK (1);
9889                         --sp;
9890                         val = *sp;
9891                         CHECK_OPSIZE (5);
9892                         token = read32 (ip + 1);
9893                         klass = mini_get_class (method, token, generic_context);
9894                         CHECK_TYPELOAD (klass);
9895
9896                         mono_save_token_info (cfg, image, token, klass);
9897
9898                         context_used = mini_class_check_context_used (cfg, klass);
9899
9900                         if (generic_class_is_reference_type (cfg, klass)) {
9901                                 *sp++ = val;
9902                                 ip += 5;
9903                                 break;
9904                         }
9905
9906                         if (klass == mono_defaults.void_class)
9907                                 UNVERIFIED;
9908                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9909                                 UNVERIFIED;
9910                         /* frequent check in generic code: box (struct), brtrue */
9911
9912                         // FIXME: LLVM can't handle the inconsistent bb linking
9913                         if (!mono_class_is_nullable (klass) &&
9914                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9915                                 (ip [5] == CEE_BRTRUE || 
9916                                  ip [5] == CEE_BRTRUE_S ||
9917                                  ip [5] == CEE_BRFALSE ||
9918                                  ip [5] == CEE_BRFALSE_S)) {
9919                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9920                                 int dreg;
9921                                 MonoBasicBlock *true_bb, *false_bb;
9922
9923                                 ip += 5;
9924
9925                                 if (cfg->verbose_level > 3) {
9926                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9927                                         printf ("<box+brtrue opt>\n");
9928                                 }
9929
9930                                 switch (*ip) {
9931                                 case CEE_BRTRUE_S:
9932                                 case CEE_BRFALSE_S:
9933                                         CHECK_OPSIZE (2);
9934                                         ip++;
9935                                         target = ip + 1 + (signed char)(*ip);
9936                                         ip++;
9937                                         break;
9938                                 case CEE_BRTRUE:
9939                                 case CEE_BRFALSE:
9940                                         CHECK_OPSIZE (5);
9941                                         ip++;
9942                                         target = ip + 4 + (gint)(read32 (ip));
9943                                         ip += 4;
9944                                         break;
9945                                 default:
9946                                         g_assert_not_reached ();
9947                                 }
9948
9949                                 /* 
9950                                  * We need to link both bblocks, since it is needed for handling stack
9951                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9952                                  * Branching to only one of them would lead to inconsistencies, so
9953                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9954                                  */
9955                                 GET_BBLOCK (cfg, true_bb, target);
9956                                 GET_BBLOCK (cfg, false_bb, ip);
9957
9958                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9959                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9960
9961                                 if (sp != stack_start) {
9962                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9963                                         sp = stack_start;
9964                                         CHECK_UNVERIFIABLE (cfg);
9965                                 }
9966
9967                                 if (COMPILE_LLVM (cfg)) {
9968                                         dreg = alloc_ireg (cfg);
9969                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9970                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9971
9972                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9973                                 } else {
9974                                         /* The JIT can't eliminate the iconst+compare */
9975                                         MONO_INST_NEW (cfg, ins, OP_BR);
9976                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9977                                         MONO_ADD_INS (cfg->cbb, ins);
9978                                 }
9979
9980                                 start_new_bblock = 1;
9981                                 break;
9982                         }
9983
9984                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9985
9986                         CHECK_CFG_EXCEPTION;
9987                         ip += 5;
9988                         inline_costs += 1;
9989                         break;
9990                 }
9991                 case CEE_UNBOX: {
9992                         CHECK_STACK (1);
9993                         --sp;
9994                         CHECK_OPSIZE (5);
9995                         token = read32 (ip + 1);
9996                         klass = mini_get_class (method, token, generic_context);
9997                         CHECK_TYPELOAD (klass);
9998
9999                         mono_save_token_info (cfg, image, token, klass);
10000
10001                         context_used = mini_class_check_context_used (cfg, klass);
10002
10003                         if (mono_class_is_nullable (klass)) {
10004                                 MonoInst *val;
10005
10006                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10007                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10008
10009                                 *sp++= ins;
10010                         } else {
10011                                 ins = handle_unbox (cfg, klass, sp, context_used);
10012                                 *sp++ = ins;
10013                         }
10014                         ip += 5;
10015                         inline_costs += 2;
10016                         break;
10017                 }
10018                 case CEE_LDFLD:
10019                 case CEE_LDFLDA:
10020                 case CEE_STFLD:
10021                 case CEE_LDSFLD:
10022                 case CEE_LDSFLDA:
10023                 case CEE_STSFLD: {
10024                         MonoClassField *field;
10025 #ifndef DISABLE_REMOTING
10026                         int costs;
10027 #endif
10028                         guint foffset;
10029                         gboolean is_instance;
10030                         int op;
10031                         gpointer addr = NULL;
10032                         gboolean is_special_static;
10033                         MonoType *ftype;
10034                         MonoInst *store_val = NULL;
10035                         MonoInst *thread_ins;
10036
10037                         op = *ip;
10038                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10039                         if (is_instance) {
10040                                 if (op == CEE_STFLD) {
10041                                         CHECK_STACK (2);
10042                                         sp -= 2;
10043                                         store_val = sp [1];
10044                                 } else {
10045                                         CHECK_STACK (1);
10046                                         --sp;
10047                                 }
10048                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10049                                         UNVERIFIED;
10050                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10051                                         UNVERIFIED;
10052                         } else {
10053                                 if (op == CEE_STSFLD) {
10054                                         CHECK_STACK (1);
10055                                         sp--;
10056                                         store_val = sp [0];
10057                                 }
10058                         }
10059
10060                         CHECK_OPSIZE (5);
10061                         token = read32 (ip + 1);
10062                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10063                                 field = mono_method_get_wrapper_data (method, token);
10064                                 klass = field->parent;
10065                         }
10066                         else {
10067                                 field = mono_field_from_token (image, token, &klass, generic_context);
10068                         }
10069                         if (!field)
10070                                 LOAD_ERROR;
10071                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10072                                 FIELD_ACCESS_FAILURE;
10073                         mono_class_init (klass);
10074
10075                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10076                                 UNVERIFIED;
10077
10078                         /* if the class is Critical then transparent code cannot access it's fields */
10079                         if (!is_instance && mono_security_core_clr_enabled ())
10080                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10081
10082                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10083                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10084                         if (mono_security_core_clr_enabled ())
10085                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10086                         */
10087
10088                         /*
10089                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10090                          * the static case.
10091                          */
10092                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10093                                 switch (op) {
10094                                 case CEE_LDFLD:
10095                                         op = CEE_LDSFLD;
10096                                         break;
10097                                 case CEE_STFLD:
10098                                         op = CEE_STSFLD;
10099                                         break;
10100                                 case CEE_LDFLDA:
10101                                         op = CEE_LDSFLDA;
10102                                         break;
10103                                 default:
10104                                         g_assert_not_reached ();
10105                                 }
10106                                 is_instance = FALSE;
10107                         }
10108
10109                         context_used = mini_class_check_context_used (cfg, klass);
10110
10111                         /* INSTANCE CASE */
10112
10113                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10114                         if (op == CEE_STFLD) {
10115                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10116                                         UNVERIFIED;
10117 #ifndef DISABLE_REMOTING
10118                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10119                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10120                                         MonoInst *iargs [5];
10121
10122                                         GSHAREDVT_FAILURE (op);
10123
10124                                         iargs [0] = sp [0];
10125                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10126                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10127                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10128                                                     field->offset);
10129                                         iargs [4] = sp [1];
10130
10131                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10132                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10133                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
10134                                                 CHECK_CFG_EXCEPTION;
10135                                                 g_assert (costs > 0);
10136                                                       
10137                                                 cfg->real_offset += 5;
10138                                                 bblock = cfg->cbb;
10139
10140                                                 inline_costs += costs;
10141                                         } else {
10142                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10143                                         }
10144                                 } else
10145 #endif
10146                                 {
10147                                         MonoInst *store;
10148
10149                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10150
10151                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10152                                                 MonoInst *offset_ins;
10153
10154                                                 context_used = mini_class_check_context_used (cfg, klass);
10155
10156                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10157                                                 dreg = alloc_ireg_mp (cfg);
10158                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10159                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10160                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10161                                         } else {
10162                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10163                                         }
10164                                         if (sp [0]->opcode != OP_LDADDR)
10165                                                 store->flags |= MONO_INST_FAULT;
10166
10167                                 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)) {
10168                                         /* insert call to write barrier */
10169                                         MonoInst *ptr;
10170                                         int dreg;
10171
10172                                         dreg = alloc_ireg_mp (cfg);
10173                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10174                                         emit_write_barrier (cfg, ptr, sp [1]);
10175                                 }
10176
10177                                         store->flags |= ins_flag;
10178                                 }
10179                                 ins_flag = 0;
10180                                 ip += 5;
10181                                 break;
10182                         }
10183
10184 #ifndef DISABLE_REMOTING
10185                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10186                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10187                                 MonoInst *iargs [4];
10188
10189                                 GSHAREDVT_FAILURE (op);
10190
10191                                 iargs [0] = sp [0];
10192                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10193                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10194                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10195                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10196                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10197                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
10198                                         CHECK_CFG_EXCEPTION;
10199                                         bblock = cfg->cbb;
10200                                         g_assert (costs > 0);
10201                                                       
10202                                         cfg->real_offset += 5;
10203
10204                                         *sp++ = iargs [0];
10205
10206                                         inline_costs += costs;
10207                                 } else {
10208                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10209                                         *sp++ = ins;
10210                                 }
10211                         } else 
10212 #endif
10213                         if (is_instance) {
10214                                 if (sp [0]->type == STACK_VTYPE) {
10215                                         MonoInst *var;
10216
10217                                         /* Have to compute the address of the variable */
10218
10219                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10220                                         if (!var)
10221                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10222                                         else
10223                                                 g_assert (var->klass == klass);
10224                                         
10225                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10226                                         sp [0] = ins;
10227                                 }
10228
10229                                 if (op == CEE_LDFLDA) {
10230                                         if (is_magic_tls_access (field)) {
10231                                                 GSHAREDVT_FAILURE (*ip);
10232                                                 ins = sp [0];
10233                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10234                                         } else {
10235                                                 if (sp [0]->type == STACK_OBJ) {
10236                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10237                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10238                                                 }
10239
10240                                                 dreg = alloc_ireg_mp (cfg);
10241
10242                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10243                                                         MonoInst *offset_ins;
10244
10245                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10246                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10247                                                 } else {
10248                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10249                                                 }
10250                                                 ins->klass = mono_class_from_mono_type (field->type);
10251                                                 ins->type = STACK_MP;
10252                                                 *sp++ = ins;
10253                                         }
10254                                 } else {
10255                                         MonoInst *load;
10256
10257                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10258
10259                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10260                                                 MonoInst *offset_ins;
10261
10262                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10263                                                 dreg = alloc_ireg_mp (cfg);
10264                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10265                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10266                                         } else {
10267                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10268                                         }
10269                                         load->flags |= ins_flag;
10270                                         if (sp [0]->opcode != OP_LDADDR)
10271                                                 load->flags |= MONO_INST_FAULT;
10272                                         *sp++ = load;
10273                                 }
10274                         }
10275
10276                         if (is_instance) {
10277                                 ins_flag = 0;
10278                                 ip += 5;
10279                                 break;
10280                         }
10281
10282                         /* STATIC CASE */
10283
10284                         /*
10285                          * We can only support shared generic static
10286                          * field access on architectures where the
10287                          * trampoline code has been extended to handle
10288                          * the generic class init.
10289                          */
10290 #ifndef MONO_ARCH_VTABLE_REG
10291                         GENERIC_SHARING_FAILURE (op);
10292 #endif
10293
10294                         context_used = mini_class_check_context_used (cfg, klass);
10295
10296                         ftype = mono_field_get_type (field);
10297
10298                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10299                                 UNVERIFIED;
10300
10301                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10302                          * to be called here.
10303                          */
10304                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10305                                 mono_class_vtable (cfg->domain, klass);
10306                                 CHECK_TYPELOAD (klass);
10307                         }
10308                         mono_domain_lock (cfg->domain);
10309                         if (cfg->domain->special_static_fields)
10310                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10311                         mono_domain_unlock (cfg->domain);
10312
10313                         is_special_static = mono_class_field_is_special_static (field);
10314
10315                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10316                                 thread_ins = mono_get_thread_intrinsic (cfg);
10317                         else
10318                                 thread_ins = NULL;
10319
10320                         /* Generate IR to compute the field address */
10321                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10322                                 /*
10323                                  * Fast access to TLS data
10324                                  * Inline version of get_thread_static_data () in
10325                                  * threads.c.
10326                                  */
10327                                 guint32 offset;
10328                                 int idx, static_data_reg, array_reg, dreg;
10329
10330                                 GSHAREDVT_FAILURE (op);
10331
10332                                 // offset &= 0x7fffffff;
10333                                 // idx = (offset >> 24) - 1;
10334                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10335                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10336                                 static_data_reg = alloc_ireg (cfg);
10337                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10338
10339                                 if (cfg->compile_aot) {
10340                                         int offset_reg, offset2_reg, idx_reg;
10341
10342                                         /* For TLS variables, this will return the TLS offset */
10343                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10344                                         offset_reg = ins->dreg;
10345                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10346                                         idx_reg = alloc_ireg (cfg);
10347                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10348                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10349                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10350                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10351                                         array_reg = alloc_ireg (cfg);
10352                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10353                                         offset2_reg = alloc_ireg (cfg);
10354                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10355                                         dreg = alloc_ireg (cfg);
10356                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10357                                 } else {
10358                                         offset = (gsize)addr & 0x7fffffff;
10359                                         idx = (offset >> 24) - 1;
10360
10361                                         array_reg = alloc_ireg (cfg);
10362                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10363                                         dreg = alloc_ireg (cfg);
10364                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10365                                 }
10366                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10367                                         (cfg->compile_aot && is_special_static) ||
10368                                         (context_used && is_special_static)) {
10369                                 MonoInst *iargs [2];
10370
10371                                 g_assert (field->parent);
10372                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10373                                 if (context_used) {
10374                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10375                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10376                                 } else {
10377                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10378                                 }
10379                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10380                         } else if (context_used) {
10381                                 MonoInst *static_data;
10382
10383                                 /*
10384                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10385                                         method->klass->name_space, method->klass->name, method->name,
10386                                         depth, field->offset);
10387                                 */
10388
10389                                 if (mono_class_needs_cctor_run (klass, method))
10390                                         emit_generic_class_init (cfg, klass);
10391
10392                                 /*
10393                                  * The pointer we're computing here is
10394                                  *
10395                                  *   super_info.static_data + field->offset
10396                                  */
10397                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10398                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10399
10400                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10401                                         MonoInst *offset_ins;
10402
10403                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10404                                         dreg = alloc_ireg_mp (cfg);
10405                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10406                                 } else if (field->offset == 0) {
10407                                         ins = static_data;
10408                                 } else {
10409                                         int addr_reg = mono_alloc_preg (cfg);
10410                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10411                                 }
10412                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10413                                 MonoInst *iargs [2];
10414
10415                                 g_assert (field->parent);
10416                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10417                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10418                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10419                         } else {
10420                                 MonoVTable *vtable = NULL;
10421
10422                                 if (!cfg->compile_aot)
10423                                         vtable = mono_class_vtable (cfg->domain, klass);
10424                                 CHECK_TYPELOAD (klass);
10425
10426                                 if (!addr) {
10427                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10428                                                 if (!(g_slist_find (class_inits, klass))) {
10429                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10430                                                         if (cfg->verbose_level > 2)
10431                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10432                                                         class_inits = g_slist_prepend (class_inits, klass);
10433                                                 }
10434                                         } else {
10435                                                 if (cfg->run_cctors) {
10436                                                         MonoException *ex;
10437                                                         /* This makes so that inline cannot trigger */
10438                                                         /* .cctors: too many apps depend on them */
10439                                                         /* running with a specific order... */
10440                                                         g_assert (vtable);
10441                                                         if (! vtable->initialized)
10442                                                                 INLINE_FAILURE ("class init");
10443                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10444                                                         if (ex) {
10445                                                                 set_exception_object (cfg, ex);
10446                                                                 goto exception_exit;
10447                                                         }
10448                                                 }
10449                                         }
10450                                         if (cfg->compile_aot)
10451                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10452                                         else {
10453                                                 g_assert (vtable);
10454                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10455                                                 g_assert (addr);
10456                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10457                                         }
10458                                 } else {
10459                                         MonoInst *iargs [1];
10460                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10461                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10462                                 }
10463                         }
10464
10465                         /* Generate IR to do the actual load/store operation */
10466
10467                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10468                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10469                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10470                                 emit_memory_barrier (cfg, FullBarrier);
10471                         }
10472
10473                         if (op == CEE_LDSFLDA) {
10474                                 ins->klass = mono_class_from_mono_type (ftype);
10475                                 ins->type = STACK_PTR;
10476                                 *sp++ = ins;
10477                         } else if (op == CEE_STSFLD) {
10478                                 MonoInst *store;
10479
10480                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10481                                 store->flags |= ins_flag;
10482                         } else {
10483                                 gboolean is_const = FALSE;
10484                                 MonoVTable *vtable = NULL;
10485                                 gpointer addr = NULL;
10486
10487                                 if (!context_used) {
10488                                         vtable = mono_class_vtable (cfg->domain, klass);
10489                                         CHECK_TYPELOAD (klass);
10490                                 }
10491                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10492                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10493                                         int ro_type = ftype->type;
10494                                         if (!addr)
10495                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10496                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10497                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10498                                         }
10499
10500                                         GSHAREDVT_FAILURE (op);
10501
10502                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10503                                         is_const = TRUE;
10504                                         switch (ro_type) {
10505                                         case MONO_TYPE_BOOLEAN:
10506                                         case MONO_TYPE_U1:
10507                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10508                                                 sp++;
10509                                                 break;
10510                                         case MONO_TYPE_I1:
10511                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10512                                                 sp++;
10513                                                 break;                                          
10514                                         case MONO_TYPE_CHAR:
10515                                         case MONO_TYPE_U2:
10516                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10517                                                 sp++;
10518                                                 break;
10519                                         case MONO_TYPE_I2:
10520                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10521                                                 sp++;
10522                                                 break;
10523                                                 break;
10524                                         case MONO_TYPE_I4:
10525                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10526                                                 sp++;
10527                                                 break;                                          
10528                                         case MONO_TYPE_U4:
10529                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10530                                                 sp++;
10531                                                 break;
10532                                         case MONO_TYPE_I:
10533                                         case MONO_TYPE_U:
10534                                         case MONO_TYPE_PTR:
10535                                         case MONO_TYPE_FNPTR:
10536                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10537                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10538                                                 sp++;
10539                                                 break;
10540                                         case MONO_TYPE_STRING:
10541                                         case MONO_TYPE_OBJECT:
10542                                         case MONO_TYPE_CLASS:
10543                                         case MONO_TYPE_SZARRAY:
10544                                         case MONO_TYPE_ARRAY:
10545                                                 if (!mono_gc_is_moving ()) {
10546                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10547                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10548                                                         sp++;
10549                                                 } else {
10550                                                         is_const = FALSE;
10551                                                 }
10552                                                 break;
10553                                         case MONO_TYPE_I8:
10554                                         case MONO_TYPE_U8:
10555                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10556                                                 sp++;
10557                                                 break;
10558                                         case MONO_TYPE_R4:
10559                                         case MONO_TYPE_R8:
10560                                         case MONO_TYPE_VALUETYPE:
10561                                         default:
10562                                                 is_const = FALSE;
10563                                                 break;
10564                                         }
10565                                 }
10566
10567                                 if (!is_const) {
10568                                         MonoInst *load;
10569
10570                                         CHECK_STACK_OVF (1);
10571
10572                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10573                                         load->flags |= ins_flag;
10574                                         ins_flag = 0;
10575                                         *sp++ = load;
10576                                 }
10577                         }
10578
10579                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10580                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10581                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10582                                 emit_memory_barrier (cfg, FullBarrier);
10583                         }
10584
10585                         ins_flag = 0;
10586                         ip += 5;
10587                         break;
10588                 }
10589                 case CEE_STOBJ:
10590                         CHECK_STACK (2);
10591                         sp -= 2;
10592                         CHECK_OPSIZE (5);
10593                         token = read32 (ip + 1);
10594                         klass = mini_get_class (method, token, generic_context);
10595                         CHECK_TYPELOAD (klass);
10596                         if (ins_flag & MONO_INST_VOLATILE) {
10597                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10598                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10599                                 emit_memory_barrier (cfg, FullBarrier);
10600                         }
10601                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10602                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10603                         ins->flags |= ins_flag;
10604                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10605                                         generic_class_is_reference_type (cfg, klass)) {
10606                                 /* insert call to write barrier */
10607                                 emit_write_barrier (cfg, sp [0], sp [1]);
10608                         }
10609                         ins_flag = 0;
10610                         ip += 5;
10611                         inline_costs += 1;
10612                         break;
10613
10614                         /*
10615                          * Array opcodes
10616                          */
10617                 case CEE_NEWARR: {
10618                         MonoInst *len_ins;
10619                         const char *data_ptr;
10620                         int data_size = 0;
10621                         guint32 field_token;
10622
10623                         CHECK_STACK (1);
10624                         --sp;
10625
10626                         CHECK_OPSIZE (5);
10627                         token = read32 (ip + 1);
10628
10629                         klass = mini_get_class (method, token, generic_context);
10630                         CHECK_TYPELOAD (klass);
10631
10632                         context_used = mini_class_check_context_used (cfg, klass);
10633
10634                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10635                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10636                                 ins->sreg1 = sp [0]->dreg;
10637                                 ins->type = STACK_I4;
10638                                 ins->dreg = alloc_ireg (cfg);
10639                                 MONO_ADD_INS (cfg->cbb, ins);
10640                                 *sp = mono_decompose_opcode (cfg, ins);
10641                         }
10642
10643                         if (context_used) {
10644                                 MonoInst *args [3];
10645                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10646                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10647
10648                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10649
10650                                 /* vtable */
10651                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10652                                         array_class, MONO_RGCTX_INFO_VTABLE);
10653                                 /* array len */
10654                                 args [1] = sp [0];
10655
10656                                 if (managed_alloc)
10657                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10658                                 else
10659                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10660                         } else {
10661                                 if (cfg->opt & MONO_OPT_SHARED) {
10662                                         /* Decompose now to avoid problems with references to the domainvar */
10663                                         MonoInst *iargs [3];
10664
10665                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10666                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10667                                         iargs [2] = sp [0];
10668
10669                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10670                                 } else {
10671                                         /* Decompose later since it is needed by abcrem */
10672                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10673                                         mono_class_vtable (cfg->domain, array_type);
10674                                         CHECK_TYPELOAD (array_type);
10675
10676                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10677                                         ins->dreg = alloc_ireg_ref (cfg);
10678                                         ins->sreg1 = sp [0]->dreg;
10679                                         ins->inst_newa_class = klass;
10680                                         ins->type = STACK_OBJ;
10681                                         ins->klass = array_type;
10682                                         MONO_ADD_INS (cfg->cbb, ins);
10683                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10684                                         cfg->cbb->has_array_access = TRUE;
10685
10686                                         /* Needed so mono_emit_load_get_addr () gets called */
10687                                         mono_get_got_var (cfg);
10688                                 }
10689                         }
10690
10691                         len_ins = sp [0];
10692                         ip += 5;
10693                         *sp++ = ins;
10694                         inline_costs += 1;
10695
10696                         /* 
10697                          * we inline/optimize the initialization sequence if possible.
10698                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10699                          * for small sizes open code the memcpy
10700                          * ensure the rva field is big enough
10701                          */
10702                         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))) {
10703                                 MonoMethod *memcpy_method = get_memcpy_method ();
10704                                 MonoInst *iargs [3];
10705                                 int add_reg = alloc_ireg_mp (cfg);
10706
10707                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10708                                 if (cfg->compile_aot) {
10709                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10710                                 } else {
10711                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10712                                 }
10713                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10714                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10715                                 ip += 11;
10716                         }
10717
10718                         break;
10719                 }
10720                 case CEE_LDLEN:
10721                         CHECK_STACK (1);
10722                         --sp;
10723                         if (sp [0]->type != STACK_OBJ)
10724                                 UNVERIFIED;
10725
10726                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10727                         ins->dreg = alloc_preg (cfg);
10728                         ins->sreg1 = sp [0]->dreg;
10729                         ins->type = STACK_I4;
10730                         /* This flag will be inherited by the decomposition */
10731                         ins->flags |= MONO_INST_FAULT;
10732                         MONO_ADD_INS (cfg->cbb, ins);
10733                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10734                         cfg->cbb->has_array_access = TRUE;
10735                         ip ++;
10736                         *sp++ = ins;
10737                         break;
10738                 case CEE_LDELEMA:
10739                         CHECK_STACK (2);
10740                         sp -= 2;
10741                         CHECK_OPSIZE (5);
10742                         if (sp [0]->type != STACK_OBJ)
10743                                 UNVERIFIED;
10744
10745                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10746
10747                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10748                         CHECK_TYPELOAD (klass);
10749                         /* we need to make sure that this array is exactly the type it needs
10750                          * to be for correctness. the wrappers are lax with their usage
10751                          * so we need to ignore them here
10752                          */
10753                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10754                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10755                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10756                                 CHECK_TYPELOAD (array_class);
10757                         }
10758
10759                         readonly = FALSE;
10760                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10761                         *sp++ = ins;
10762                         ip += 5;
10763                         break;
10764                 case CEE_LDELEM:
10765                 case CEE_LDELEM_I1:
10766                 case CEE_LDELEM_U1:
10767                 case CEE_LDELEM_I2:
10768                 case CEE_LDELEM_U2:
10769                 case CEE_LDELEM_I4:
10770                 case CEE_LDELEM_U4:
10771                 case CEE_LDELEM_I8:
10772                 case CEE_LDELEM_I:
10773                 case CEE_LDELEM_R4:
10774                 case CEE_LDELEM_R8:
10775                 case CEE_LDELEM_REF: {
10776                         MonoInst *addr;
10777
10778                         CHECK_STACK (2);
10779                         sp -= 2;
10780
10781                         if (*ip == CEE_LDELEM) {
10782                                 CHECK_OPSIZE (5);
10783                                 token = read32 (ip + 1);
10784                                 klass = mini_get_class (method, token, generic_context);
10785                                 CHECK_TYPELOAD (klass);
10786                                 mono_class_init (klass);
10787                         }
10788                         else
10789                                 klass = array_access_to_klass (*ip);
10790
10791                         if (sp [0]->type != STACK_OBJ)
10792                                 UNVERIFIED;
10793
10794                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10795
10796                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10797                                 // FIXME-VT: OP_ICONST optimization
10798                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10799                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10800                                 ins->opcode = OP_LOADV_MEMBASE;
10801                         } else if (sp [1]->opcode == OP_ICONST) {
10802                                 int array_reg = sp [0]->dreg;
10803                                 int index_reg = sp [1]->dreg;
10804                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10805
10806                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10807                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10808                         } else {
10809                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10810                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10811                         }
10812                         *sp++ = ins;
10813                         if (*ip == CEE_LDELEM)
10814                                 ip += 5;
10815                         else
10816                                 ++ip;
10817                         break;
10818                 }
10819                 case CEE_STELEM_I:
10820                 case CEE_STELEM_I1:
10821                 case CEE_STELEM_I2:
10822                 case CEE_STELEM_I4:
10823                 case CEE_STELEM_I8:
10824                 case CEE_STELEM_R4:
10825                 case CEE_STELEM_R8:
10826                 case CEE_STELEM_REF:
10827                 case CEE_STELEM: {
10828                         CHECK_STACK (3);
10829                         sp -= 3;
10830
10831                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10832
10833                         if (*ip == CEE_STELEM) {
10834                                 CHECK_OPSIZE (5);
10835                                 token = read32 (ip + 1);
10836                                 klass = mini_get_class (method, token, generic_context);
10837                                 CHECK_TYPELOAD (klass);
10838                                 mono_class_init (klass);
10839                         }
10840                         else
10841                                 klass = array_access_to_klass (*ip);
10842
10843                         if (sp [0]->type != STACK_OBJ)
10844                                 UNVERIFIED;
10845
10846                         emit_array_store (cfg, klass, sp, TRUE);
10847
10848                         if (*ip == CEE_STELEM)
10849                                 ip += 5;
10850                         else
10851                                 ++ip;
10852                         inline_costs += 1;
10853                         break;
10854                 }
10855                 case CEE_CKFINITE: {
10856                         CHECK_STACK (1);
10857                         --sp;
10858
10859                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10860                         ins->sreg1 = sp [0]->dreg;
10861                         ins->dreg = alloc_freg (cfg);
10862                         ins->type = STACK_R8;
10863                         MONO_ADD_INS (bblock, ins);
10864
10865                         *sp++ = mono_decompose_opcode (cfg, ins);
10866
10867                         ++ip;
10868                         break;
10869                 }
10870                 case CEE_REFANYVAL: {
10871                         MonoInst *src_var, *src;
10872
10873                         int klass_reg = alloc_preg (cfg);
10874                         int dreg = alloc_preg (cfg);
10875
10876                         GSHAREDVT_FAILURE (*ip);
10877
10878                         CHECK_STACK (1);
10879                         MONO_INST_NEW (cfg, ins, *ip);
10880                         --sp;
10881                         CHECK_OPSIZE (5);
10882                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10883                         CHECK_TYPELOAD (klass);
10884                         mono_class_init (klass);
10885
10886                         context_used = mini_class_check_context_used (cfg, klass);
10887
10888                         // FIXME:
10889                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10890                         if (!src_var)
10891                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10892                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10893                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10894
10895                         if (context_used) {
10896                                 MonoInst *klass_ins;
10897
10898                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10899                                                 klass, MONO_RGCTX_INFO_KLASS);
10900
10901                                 // FIXME:
10902                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10903                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10904                         } else {
10905                                 mini_emit_class_check (cfg, klass_reg, klass);
10906                         }
10907                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10908                         ins->type = STACK_MP;
10909                         *sp++ = ins;
10910                         ip += 5;
10911                         break;
10912                 }
10913                 case CEE_MKREFANY: {
10914                         MonoInst *loc, *addr;
10915
10916                         GSHAREDVT_FAILURE (*ip);
10917
10918                         CHECK_STACK (1);
10919                         MONO_INST_NEW (cfg, ins, *ip);
10920                         --sp;
10921                         CHECK_OPSIZE (5);
10922                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10923                         CHECK_TYPELOAD (klass);
10924                         mono_class_init (klass);
10925
10926                         context_used = mini_class_check_context_used (cfg, klass);
10927
10928                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10929                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10930
10931                         if (context_used) {
10932                                 MonoInst *const_ins;
10933                                 int type_reg = alloc_preg (cfg);
10934
10935                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10936                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10937                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10938                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10939                         } else if (cfg->compile_aot) {
10940                                 int const_reg = alloc_preg (cfg);
10941                                 int type_reg = alloc_preg (cfg);
10942
10943                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10944                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10945                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10946                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10947                         } else {
10948                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10949                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10950                         }
10951                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10952
10953                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10954                         ins->type = STACK_VTYPE;
10955                         ins->klass = mono_defaults.typed_reference_class;
10956                         *sp++ = ins;
10957                         ip += 5;
10958                         break;
10959                 }
10960                 case CEE_LDTOKEN: {
10961                         gpointer handle;
10962                         MonoClass *handle_class;
10963
10964                         CHECK_STACK_OVF (1);
10965
10966                         CHECK_OPSIZE (5);
10967                         n = read32 (ip + 1);
10968
10969                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10970                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10971                                 handle = mono_method_get_wrapper_data (method, n);
10972                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10973                                 if (handle_class == mono_defaults.typehandle_class)
10974                                         handle = &((MonoClass*)handle)->byval_arg;
10975                         }
10976                         else {
10977                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10978                         }
10979                         if (!handle)
10980                                 LOAD_ERROR;
10981                         mono_class_init (handle_class);
10982                         if (cfg->generic_sharing_context) {
10983                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10984                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10985                                         /* This case handles ldtoken
10986                                            of an open type, like for
10987                                            typeof(Gen<>). */
10988                                         context_used = 0;
10989                                 } else if (handle_class == mono_defaults.typehandle_class) {
10990                                         /* If we get a MONO_TYPE_CLASS
10991                                            then we need to provide the
10992                                            open type, not an
10993                                            instantiation of it. */
10994                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10995                                                 context_used = 0;
10996                                         else
10997                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10998                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10999                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11000                                 else if (handle_class == mono_defaults.methodhandle_class)
11001                                         context_used = mini_method_check_context_used (cfg, handle);
11002                                 else
11003                                         g_assert_not_reached ();
11004                         }
11005
11006                         if ((cfg->opt & MONO_OPT_SHARED) &&
11007                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11008                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11009                                 MonoInst *addr, *vtvar, *iargs [3];
11010                                 int method_context_used;
11011
11012                                 method_context_used = mini_method_check_context_used (cfg, method);
11013
11014                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11015
11016                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11017                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11018                                 if (method_context_used) {
11019                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11020                                                 method, MONO_RGCTX_INFO_METHOD);
11021                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11022                                 } else {
11023                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11024                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11025                                 }
11026                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11027
11028                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11029
11030                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11031                         } else {
11032                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11033                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11034                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11035                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11036                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11037                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11038
11039                                         mono_class_init (tclass);
11040                                         if (context_used) {
11041                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11042                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11043                                         } else if (cfg->compile_aot) {
11044                                                 if (method->wrapper_type) {
11045                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
11046                                                                 /* Special case for static synchronized wrappers */
11047                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11048                                                         } else {
11049                                                                 /* FIXME: n is not a normal token */
11050                                                                 DISABLE_AOT (cfg);
11051                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11052                                                         }
11053                                                 } else {
11054                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11055                                                 }
11056                                         } else {
11057                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11058                                         }
11059                                         ins->type = STACK_OBJ;
11060                                         ins->klass = cmethod->klass;
11061                                         ip += 5;
11062                                 } else {
11063                                         MonoInst *addr, *vtvar;
11064
11065                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11066
11067                                         if (context_used) {
11068                                                 if (handle_class == mono_defaults.typehandle_class) {
11069                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11070                                                                         mono_class_from_mono_type (handle),
11071                                                                         MONO_RGCTX_INFO_TYPE);
11072                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11073                                                         ins = emit_get_rgctx_method (cfg, context_used,
11074                                                                         handle, MONO_RGCTX_INFO_METHOD);
11075                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11076                                                         ins = emit_get_rgctx_field (cfg, context_used,
11077                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11078                                                 } else {
11079                                                         g_assert_not_reached ();
11080                                                 }
11081                                         } else if (cfg->compile_aot) {
11082                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11083                                         } else {
11084                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11085                                         }
11086                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11087                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11088                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11089                                 }
11090                         }
11091
11092                         *sp++ = ins;
11093                         ip += 5;
11094                         break;
11095                 }
11096                 case CEE_THROW:
11097                         CHECK_STACK (1);
11098                         MONO_INST_NEW (cfg, ins, OP_THROW);
11099                         --sp;
11100                         ins->sreg1 = sp [0]->dreg;
11101                         ip++;
11102                         bblock->out_of_line = TRUE;
11103                         MONO_ADD_INS (bblock, ins);
11104                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11105                         MONO_ADD_INS (bblock, ins);
11106                         sp = stack_start;
11107                         
11108                         link_bblock (cfg, bblock, end_bblock);
11109                         start_new_bblock = 1;
11110                         break;
11111                 case CEE_ENDFINALLY:
11112                         /* mono_save_seq_point_info () depends on this */
11113                         if (sp != stack_start)
11114                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11115                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11116                         MONO_ADD_INS (bblock, ins);
11117                         ip++;
11118                         start_new_bblock = 1;
11119
11120                         /*
11121                          * Control will leave the method so empty the stack, otherwise
11122                          * the next basic block will start with a nonempty stack.
11123                          */
11124                         while (sp != stack_start) {
11125                                 sp--;
11126                         }
11127                         break;
11128                 case CEE_LEAVE:
11129                 case CEE_LEAVE_S: {
11130                         GList *handlers;
11131
11132                         if (*ip == CEE_LEAVE) {
11133                                 CHECK_OPSIZE (5);
11134                                 target = ip + 5 + (gint32)read32(ip + 1);
11135                         } else {
11136                                 CHECK_OPSIZE (2);
11137                                 target = ip + 2 + (signed char)(ip [1]);
11138                         }
11139
11140                         /* empty the stack */
11141                         while (sp != stack_start) {
11142                                 sp--;
11143                         }
11144
11145                         /* 
11146                          * If this leave statement is in a catch block, check for a
11147                          * pending exception, and rethrow it if necessary.
11148                          * We avoid doing this in runtime invoke wrappers, since those are called
11149                          * by native code which excepts the wrapper to catch all exceptions.
11150                          */
11151                         for (i = 0; i < header->num_clauses; ++i) {
11152                                 MonoExceptionClause *clause = &header->clauses [i];
11153
11154                                 /* 
11155                                  * Use <= in the final comparison to handle clauses with multiple
11156                                  * leave statements, like in bug #78024.
11157                                  * The ordering of the exception clauses guarantees that we find the
11158                                  * innermost clause.
11159                                  */
11160                                 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) {
11161                                         MonoInst *exc_ins;
11162                                         MonoBasicBlock *dont_throw;
11163
11164                                         /*
11165                                           MonoInst *load;
11166
11167                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11168                                         */
11169
11170                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11171
11172                                         NEW_BBLOCK (cfg, dont_throw);
11173
11174                                         /*
11175                                          * Currently, we always rethrow the abort exception, despite the 
11176                                          * fact that this is not correct. See thread6.cs for an example. 
11177                                          * But propagating the abort exception is more important than 
11178                                          * getting the sematics right.
11179                                          */
11180                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11181                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11182                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11183
11184                                         MONO_START_BB (cfg, dont_throw);
11185                                         bblock = cfg->cbb;
11186                                 }
11187                         }
11188
11189                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11190                                 GList *tmp;
11191                                 MonoExceptionClause *clause;
11192
11193                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11194                                         clause = tmp->data;
11195                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11196                                         g_assert (tblock);
11197                                         link_bblock (cfg, bblock, tblock);
11198                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11199                                         ins->inst_target_bb = tblock;
11200                                         ins->inst_eh_block = clause;
11201                                         MONO_ADD_INS (bblock, ins);
11202                                         bblock->has_call_handler = 1;
11203                                         if (COMPILE_LLVM (cfg)) {
11204                                                 MonoBasicBlock *target_bb;
11205
11206                                                 /* 
11207                                                  * Link the finally bblock with the target, since it will
11208                                                  * conceptually branch there.
11209                                                  * FIXME: Have to link the bblock containing the endfinally.
11210                                                  */
11211                                                 GET_BBLOCK (cfg, target_bb, target);
11212                                                 link_bblock (cfg, tblock, target_bb);
11213                                         }
11214                                 }
11215                                 g_list_free (handlers);
11216                         } 
11217
11218                         MONO_INST_NEW (cfg, ins, OP_BR);
11219                         MONO_ADD_INS (bblock, ins);
11220                         GET_BBLOCK (cfg, tblock, target);
11221                         link_bblock (cfg, bblock, tblock);
11222                         ins->inst_target_bb = tblock;
11223                         start_new_bblock = 1;
11224
11225                         if (*ip == CEE_LEAVE)
11226                                 ip += 5;
11227                         else
11228                                 ip += 2;
11229
11230                         break;
11231                 }
11232
11233                         /*
11234                          * Mono specific opcodes
11235                          */
11236                 case MONO_CUSTOM_PREFIX: {
11237
11238                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11239
11240                         CHECK_OPSIZE (2);
11241                         switch (ip [1]) {
11242                         case CEE_MONO_ICALL: {
11243                                 gpointer func;
11244                                 MonoJitICallInfo *info;
11245
11246                                 token = read32 (ip + 2);
11247                                 func = mono_method_get_wrapper_data (method, token);
11248                                 info = mono_find_jit_icall_by_addr (func);
11249                                 if (!info)
11250                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11251                                 g_assert (info);
11252
11253                                 CHECK_STACK (info->sig->param_count);
11254                                 sp -= info->sig->param_count;
11255
11256                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11257                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11258                                         *sp++ = ins;
11259
11260                                 ip += 6;
11261                                 inline_costs += 10 * num_calls++;
11262
11263                                 break;
11264                         }
11265                         case CEE_MONO_LDPTR: {
11266                                 gpointer ptr;
11267
11268                                 CHECK_STACK_OVF (1);
11269                                 CHECK_OPSIZE (6);
11270                                 token = read32 (ip + 2);
11271
11272                                 ptr = mono_method_get_wrapper_data (method, token);
11273                                 /* FIXME: Generalize this */
11274                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11275                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11276                                         *sp++ = ins;
11277                                         ip += 6;
11278                                         break;
11279                                 }
11280                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11281                                 *sp++ = ins;
11282                                 ip += 6;
11283                                 inline_costs += 10 * num_calls++;
11284                                 /* Can't embed random pointers into AOT code */
11285                                 DISABLE_AOT (cfg);
11286                                 break;
11287                         }
11288                         case CEE_MONO_JIT_ICALL_ADDR: {
11289                                 MonoJitICallInfo *callinfo;
11290                                 gpointer ptr;
11291
11292                                 CHECK_STACK_OVF (1);
11293                                 CHECK_OPSIZE (6);
11294                                 token = read32 (ip + 2);
11295
11296                                 ptr = mono_method_get_wrapper_data (method, token);
11297                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11298                                 g_assert (callinfo);
11299                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11300                                 *sp++ = ins;
11301                                 ip += 6;
11302                                 inline_costs += 10 * num_calls++;
11303                                 break;
11304                         }
11305                         case CEE_MONO_ICALL_ADDR: {
11306                                 MonoMethod *cmethod;
11307                                 gpointer ptr;
11308
11309                                 CHECK_STACK_OVF (1);
11310                                 CHECK_OPSIZE (6);
11311                                 token = read32 (ip + 2);
11312
11313                                 cmethod = mono_method_get_wrapper_data (method, token);
11314
11315                                 if (cfg->compile_aot) {
11316                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11317                                 } else {
11318                                         ptr = mono_lookup_internal_call (cmethod);
11319                                         g_assert (ptr);
11320                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11321                                 }
11322                                 *sp++ = ins;
11323                                 ip += 6;
11324                                 break;
11325                         }
11326                         case CEE_MONO_VTADDR: {
11327                                 MonoInst *src_var, *src;
11328
11329                                 CHECK_STACK (1);
11330                                 --sp;
11331
11332                                 // FIXME:
11333                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11334                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11335                                 *sp++ = src;
11336                                 ip += 2;
11337                                 break;
11338                         }
11339                         case CEE_MONO_NEWOBJ: {
11340                                 MonoInst *iargs [2];
11341
11342                                 CHECK_STACK_OVF (1);
11343                                 CHECK_OPSIZE (6);
11344                                 token = read32 (ip + 2);
11345                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11346                                 mono_class_init (klass);
11347                                 NEW_DOMAINCONST (cfg, iargs [0]);
11348                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11349                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11350                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11351                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11352                                 ip += 6;
11353                                 inline_costs += 10 * num_calls++;
11354                                 break;
11355                         }
11356                         case CEE_MONO_OBJADDR:
11357                                 CHECK_STACK (1);
11358                                 --sp;
11359                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11360                                 ins->dreg = alloc_ireg_mp (cfg);
11361                                 ins->sreg1 = sp [0]->dreg;
11362                                 ins->type = STACK_MP;
11363                                 MONO_ADD_INS (cfg->cbb, ins);
11364                                 *sp++ = ins;
11365                                 ip += 2;
11366                                 break;
11367                         case CEE_MONO_LDNATIVEOBJ:
11368                                 /*
11369                                  * Similar to LDOBJ, but instead load the unmanaged 
11370                                  * representation of the vtype to the stack.
11371                                  */
11372                                 CHECK_STACK (1);
11373                                 CHECK_OPSIZE (6);
11374                                 --sp;
11375                                 token = read32 (ip + 2);
11376                                 klass = mono_method_get_wrapper_data (method, token);
11377                                 g_assert (klass->valuetype);
11378                                 mono_class_init (klass);
11379
11380                                 {
11381                                         MonoInst *src, *dest, *temp;
11382
11383                                         src = sp [0];
11384                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11385                                         temp->backend.is_pinvoke = 1;
11386                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11387                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11388
11389                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11390                                         dest->type = STACK_VTYPE;
11391                                         dest->klass = klass;
11392
11393                                         *sp ++ = dest;
11394                                         ip += 6;
11395                                 }
11396                                 break;
11397                         case CEE_MONO_RETOBJ: {
11398                                 /*
11399                                  * Same as RET, but return the native representation of a vtype
11400                                  * to the caller.
11401                                  */
11402                                 g_assert (cfg->ret);
11403                                 g_assert (mono_method_signature (method)->pinvoke); 
11404                                 CHECK_STACK (1);
11405                                 --sp;
11406                                 
11407                                 CHECK_OPSIZE (6);
11408                                 token = read32 (ip + 2);    
11409                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11410
11411                                 if (!cfg->vret_addr) {
11412                                         g_assert (cfg->ret_var_is_local);
11413
11414                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11415                                 } else {
11416                                         EMIT_NEW_RETLOADA (cfg, ins);
11417                                 }
11418                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11419                                 
11420                                 if (sp != stack_start)
11421                                         UNVERIFIED;
11422                                 
11423                                 MONO_INST_NEW (cfg, ins, OP_BR);
11424                                 ins->inst_target_bb = end_bblock;
11425                                 MONO_ADD_INS (bblock, ins);
11426                                 link_bblock (cfg, bblock, end_bblock);
11427                                 start_new_bblock = 1;
11428                                 ip += 6;
11429                                 break;
11430                         }
11431                         case CEE_MONO_CISINST:
11432                         case CEE_MONO_CCASTCLASS: {
11433                                 int token;
11434                                 CHECK_STACK (1);
11435                                 --sp;
11436                                 CHECK_OPSIZE (6);
11437                                 token = read32 (ip + 2);
11438                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11439                                 if (ip [1] == CEE_MONO_CISINST)
11440                                         ins = handle_cisinst (cfg, klass, sp [0]);
11441                                 else
11442                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11443                                 bblock = cfg->cbb;
11444                                 *sp++ = ins;
11445                                 ip += 6;
11446                                 break;
11447                         }
11448                         case CEE_MONO_SAVE_LMF:
11449                         case CEE_MONO_RESTORE_LMF:
11450 #ifdef MONO_ARCH_HAVE_LMF_OPS
11451                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11452                                 MONO_ADD_INS (bblock, ins);
11453                                 cfg->need_lmf_area = TRUE;
11454 #endif
11455                                 ip += 2;
11456                                 break;
11457                         case CEE_MONO_CLASSCONST:
11458                                 CHECK_STACK_OVF (1);
11459                                 CHECK_OPSIZE (6);
11460                                 token = read32 (ip + 2);
11461                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11462                                 *sp++ = ins;
11463                                 ip += 6;
11464                                 inline_costs += 10 * num_calls++;
11465                                 break;
11466                         case CEE_MONO_NOT_TAKEN:
11467                                 bblock->out_of_line = TRUE;
11468                                 ip += 2;
11469                                 break;
11470                         case CEE_MONO_TLS: {
11471                                 int key;
11472
11473                                 CHECK_STACK_OVF (1);
11474                                 CHECK_OPSIZE (6);
11475                                 key = (gint32)read32 (ip + 2);
11476                                 g_assert (key < TLS_KEY_NUM);
11477
11478                                 ins = mono_create_tls_get (cfg, key);
11479                                 if (!ins) {
11480                                         if (cfg->compile_aot) {
11481                                                 DISABLE_AOT (cfg);
11482                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11483                                                 ins->dreg = alloc_preg (cfg);
11484                                                 ins->type = STACK_PTR;
11485                                         } else {
11486                                                 g_assert_not_reached ();
11487                                         }
11488                                 }
11489                                 ins->type = STACK_PTR;
11490                                 MONO_ADD_INS (bblock, ins);
11491                                 *sp++ = ins;
11492                                 ip += 6;
11493                                 break;
11494                         }
11495                         case CEE_MONO_DYN_CALL: {
11496                                 MonoCallInst *call;
11497
11498                                 /* It would be easier to call a trampoline, but that would put an
11499                                  * extra frame on the stack, confusing exception handling. So
11500                                  * implement it inline using an opcode for now.
11501                                  */
11502
11503                                 if (!cfg->dyn_call_var) {
11504                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11505                                         /* prevent it from being register allocated */
11506                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11507                                 }
11508
11509                                 /* Has to use a call inst since it local regalloc expects it */
11510                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11511                                 ins = (MonoInst*)call;
11512                                 sp -= 2;
11513                                 ins->sreg1 = sp [0]->dreg;
11514                                 ins->sreg2 = sp [1]->dreg;
11515                                 MONO_ADD_INS (bblock, ins);
11516
11517                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11518
11519                                 ip += 2;
11520                                 inline_costs += 10 * num_calls++;
11521
11522                                 break;
11523                         }
11524                         case CEE_MONO_MEMORY_BARRIER: {
11525                                 CHECK_OPSIZE (5);
11526                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11527                                 ip += 5;
11528                                 break;
11529                         }
11530                         case CEE_MONO_JIT_ATTACH: {
11531                                 MonoInst *args [16];
11532                                 MonoInst *ad_ins, *lmf_ins;
11533                                 MonoBasicBlock *next_bb = NULL;
11534
11535                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11536
11537                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11538                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11539
11540 #if TARGET_WIN32
11541                                 ad_ins = NULL;
11542                                 lmf_ins = NULL;
11543 #else
11544                                 ad_ins = mono_get_domain_intrinsic (cfg);
11545                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11546 #endif
11547
11548                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11549                                         NEW_BBLOCK (cfg, next_bb);
11550
11551                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11552                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11553                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11554
11555                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11556                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11557                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11558                                 }
11559
11560                                 if (cfg->compile_aot) {
11561                                         /* AOT code is only used in the root domain */
11562                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11563                                 } else {
11564                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11565                                 }
11566                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11567                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11568
11569                                 if (next_bb) {
11570                                         MONO_START_BB (cfg, next_bb);
11571                                         bblock = cfg->cbb;
11572                                 }
11573                                 ip += 2;
11574                                 break;
11575                         }
11576                         case CEE_MONO_JIT_DETACH: {
11577                                 MonoInst *args [16];
11578
11579                                 /* Restore the original domain */
11580                                 dreg = alloc_ireg (cfg);
11581                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11582                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11583                                 ip += 2;
11584                                 break;
11585                         }
11586                         default:
11587                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11588                                 break;
11589                         }
11590                         break;
11591                 }
11592
11593                 case CEE_PREFIX1: {
11594                         CHECK_OPSIZE (2);
11595                         switch (ip [1]) {
11596                         case CEE_ARGLIST: {
11597                                 /* somewhat similar to LDTOKEN */
11598                                 MonoInst *addr, *vtvar;
11599                                 CHECK_STACK_OVF (1);
11600                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11601
11602                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11603                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11604
11605                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11606                                 ins->type = STACK_VTYPE;
11607                                 ins->klass = mono_defaults.argumenthandle_class;
11608                                 *sp++ = ins;
11609                                 ip += 2;
11610                                 break;
11611                         }
11612                         case CEE_CEQ:
11613                         case CEE_CGT:
11614                         case CEE_CGT_UN:
11615                         case CEE_CLT:
11616                         case CEE_CLT_UN: {
11617                                 MonoInst *cmp;
11618                                 CHECK_STACK (2);
11619                                 /*
11620                                  * The following transforms:
11621                                  *    CEE_CEQ    into OP_CEQ
11622                                  *    CEE_CGT    into OP_CGT
11623                                  *    CEE_CGT_UN into OP_CGT_UN
11624                                  *    CEE_CLT    into OP_CLT
11625                                  *    CEE_CLT_UN into OP_CLT_UN
11626                                  */
11627                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11628                                 
11629                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11630                                 sp -= 2;
11631                                 cmp->sreg1 = sp [0]->dreg;
11632                                 cmp->sreg2 = sp [1]->dreg;
11633                                 type_from_op (cmp, sp [0], sp [1]);
11634                                 CHECK_TYPE (cmp);
11635                                 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))))
11636                                         cmp->opcode = OP_LCOMPARE;
11637                                 else if (sp [0]->type == STACK_R8)
11638                                         cmp->opcode = OP_FCOMPARE;
11639                                 else
11640                                         cmp->opcode = OP_ICOMPARE;
11641                                 MONO_ADD_INS (bblock, cmp);
11642                                 ins->type = STACK_I4;
11643                                 ins->dreg = alloc_dreg (cfg, ins->type);
11644                                 type_from_op (ins, sp [0], sp [1]);
11645
11646                                 if (cmp->opcode == OP_FCOMPARE) {
11647                                         /*
11648                                          * The backends expect the fceq opcodes to do the
11649                                          * comparison too.
11650                                          */
11651                                         cmp->opcode = OP_NOP;
11652                                         ins->sreg1 = cmp->sreg1;
11653                                         ins->sreg2 = cmp->sreg2;
11654                                 }
11655                                 MONO_ADD_INS (bblock, ins);
11656                                 *sp++ = ins;
11657                                 ip += 2;
11658                                 break;
11659                         }
11660                         case CEE_LDFTN: {
11661                                 MonoInst *argconst;
11662                                 MonoMethod *cil_method;
11663
11664                                 CHECK_STACK_OVF (1);
11665                                 CHECK_OPSIZE (6);
11666                                 n = read32 (ip + 2);
11667                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11668                                 if (!cmethod || mono_loader_get_last_error ())
11669                                         LOAD_ERROR;
11670                                 mono_class_init (cmethod->klass);
11671
11672                                 mono_save_token_info (cfg, image, n, cmethod);
11673
11674                                 context_used = mini_method_check_context_used (cfg, cmethod);
11675
11676                                 cil_method = cmethod;
11677                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11678                                         METHOD_ACCESS_FAILURE;
11679
11680                                 if (mono_security_cas_enabled ()) {
11681                                         if (check_linkdemand (cfg, method, cmethod))
11682                                                 INLINE_FAILURE ("linkdemand");
11683                                         CHECK_CFG_EXCEPTION;
11684                                 } else if (mono_security_core_clr_enabled ()) {
11685                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11686                                 }
11687
11688                                 /* 
11689                                  * Optimize the common case of ldftn+delegate creation
11690                                  */
11691                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11692                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11693                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11694                                                 MonoInst *target_ins;
11695                                                 MonoMethod *invoke;
11696                                                 int invoke_context_used;
11697
11698                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11699                                                 if (!invoke || !mono_method_signature (invoke))
11700                                                         LOAD_ERROR;
11701
11702                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11703
11704                                                 target_ins = sp [-1];
11705
11706                                                 if (mono_security_core_clr_enabled ())
11707                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11708
11709                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11710                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11711                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11712                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11713                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11714                                                         }
11715                                                 }
11716
11717 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11718                                                 /* FIXME: SGEN support */
11719                                                 if (invoke_context_used == 0) {
11720                                                         ip += 6;
11721                                                         if (cfg->verbose_level > 3)
11722                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11723                                                         sp --;
11724                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11725                                                         CHECK_CFG_EXCEPTION;
11726                                                         ip += 5;                        
11727                                                         sp ++;
11728                                                         break;
11729                                                 }
11730 #endif
11731                                         }
11732                                 }
11733
11734                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11735                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11736                                 *sp++ = ins;
11737                                 
11738                                 ip += 6;
11739                                 inline_costs += 10 * num_calls++;
11740                                 break;
11741                         }
11742                         case CEE_LDVIRTFTN: {
11743                                 MonoInst *args [2];
11744
11745                                 CHECK_STACK (1);
11746                                 CHECK_OPSIZE (6);
11747                                 n = read32 (ip + 2);
11748                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11749                                 if (!cmethod || mono_loader_get_last_error ())
11750                                         LOAD_ERROR;
11751                                 mono_class_init (cmethod->klass);
11752  
11753                                 context_used = mini_method_check_context_used (cfg, cmethod);
11754
11755                                 if (mono_security_cas_enabled ()) {
11756                                         if (check_linkdemand (cfg, method, cmethod))
11757                                                 INLINE_FAILURE ("linkdemand");
11758                                         CHECK_CFG_EXCEPTION;
11759                                 } else if (mono_security_core_clr_enabled ()) {
11760                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11761                                 }
11762
11763                                 --sp;
11764                                 args [0] = *sp;
11765
11766                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11767                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11768
11769                                 if (context_used)
11770                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11771                                 else
11772                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11773
11774                                 ip += 6;
11775                                 inline_costs += 10 * num_calls++;
11776                                 break;
11777                         }
11778                         case CEE_LDARG:
11779                                 CHECK_STACK_OVF (1);
11780                                 CHECK_OPSIZE (4);
11781                                 n = read16 (ip + 2);
11782                                 CHECK_ARG (n);
11783                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11784                                 *sp++ = ins;
11785                                 ip += 4;
11786                                 break;
11787                         case CEE_LDARGA:
11788                                 CHECK_STACK_OVF (1);
11789                                 CHECK_OPSIZE (4);
11790                                 n = read16 (ip + 2);
11791                                 CHECK_ARG (n);
11792                                 NEW_ARGLOADA (cfg, ins, n);
11793                                 MONO_ADD_INS (cfg->cbb, ins);
11794                                 *sp++ = ins;
11795                                 ip += 4;
11796                                 break;
11797                         case CEE_STARG:
11798                                 CHECK_STACK (1);
11799                                 --sp;
11800                                 CHECK_OPSIZE (4);
11801                                 n = read16 (ip + 2);
11802                                 CHECK_ARG (n);
11803                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11804                                         UNVERIFIED;
11805                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11806                                 ip += 4;
11807                                 break;
11808                         case CEE_LDLOC:
11809                                 CHECK_STACK_OVF (1);
11810                                 CHECK_OPSIZE (4);
11811                                 n = read16 (ip + 2);
11812                                 CHECK_LOCAL (n);
11813                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11814                                 *sp++ = ins;
11815                                 ip += 4;
11816                                 break;
11817                         case CEE_LDLOCA: {
11818                                 unsigned char *tmp_ip;
11819                                 CHECK_STACK_OVF (1);
11820                                 CHECK_OPSIZE (4);
11821                                 n = read16 (ip + 2);
11822                                 CHECK_LOCAL (n);
11823
11824                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11825                                         ip = tmp_ip;
11826                                         inline_costs += 1;
11827                                         break;
11828                                 }                       
11829                                 
11830                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11831                                 *sp++ = ins;
11832                                 ip += 4;
11833                                 break;
11834                         }
11835                         case CEE_STLOC:
11836                                 CHECK_STACK (1);
11837                                 --sp;
11838                                 CHECK_OPSIZE (4);
11839                                 n = read16 (ip + 2);
11840                                 CHECK_LOCAL (n);
11841                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11842                                         UNVERIFIED;
11843                                 emit_stloc_ir (cfg, sp, header, n);
11844                                 ip += 4;
11845                                 inline_costs += 1;
11846                                 break;
11847                         case CEE_LOCALLOC:
11848                                 CHECK_STACK (1);
11849                                 --sp;
11850                                 if (sp != stack_start) 
11851                                         UNVERIFIED;
11852                                 if (cfg->method != method) 
11853                                         /* 
11854                                          * Inlining this into a loop in a parent could lead to 
11855                                          * stack overflows which is different behavior than the
11856                                          * non-inlined case, thus disable inlining in this case.
11857                                          */
11858                                         goto inline_failure;
11859
11860                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11861                                 ins->dreg = alloc_preg (cfg);
11862                                 ins->sreg1 = sp [0]->dreg;
11863                                 ins->type = STACK_PTR;
11864                                 MONO_ADD_INS (cfg->cbb, ins);
11865
11866                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11867                                 if (init_locals)
11868                                         ins->flags |= MONO_INST_INIT;
11869
11870                                 *sp++ = ins;
11871                                 ip += 2;
11872                                 break;
11873                         case CEE_ENDFILTER: {
11874                                 MonoExceptionClause *clause, *nearest;
11875                                 int cc, nearest_num;
11876
11877                                 CHECK_STACK (1);
11878                                 --sp;
11879                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11880                                         UNVERIFIED;
11881                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11882                                 ins->sreg1 = (*sp)->dreg;
11883                                 MONO_ADD_INS (bblock, ins);
11884                                 start_new_bblock = 1;
11885                                 ip += 2;
11886
11887                                 nearest = NULL;
11888                                 nearest_num = 0;
11889                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11890                                         clause = &header->clauses [cc];
11891                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11892                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11893                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11894                                                 nearest = clause;
11895                                                 nearest_num = cc;
11896                                         }
11897                                 }
11898                                 g_assert (nearest);
11899                                 if ((ip - header->code) != nearest->handler_offset)
11900                                         UNVERIFIED;
11901
11902                                 break;
11903                         }
11904                         case CEE_UNALIGNED_:
11905                                 ins_flag |= MONO_INST_UNALIGNED;
11906                                 /* FIXME: record alignment? we can assume 1 for now */
11907                                 CHECK_OPSIZE (3);
11908                                 ip += 3;
11909                                 break;
11910                         case CEE_VOLATILE_:
11911                                 ins_flag |= MONO_INST_VOLATILE;
11912                                 ip += 2;
11913                                 break;
11914                         case CEE_TAIL_:
11915                                 ins_flag   |= MONO_INST_TAILCALL;
11916                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11917                                 /* Can't inline tail calls at this time */
11918                                 inline_costs += 100000;
11919                                 ip += 2;
11920                                 break;
11921                         case CEE_INITOBJ:
11922                                 CHECK_STACK (1);
11923                                 --sp;
11924                                 CHECK_OPSIZE (6);
11925                                 token = read32 (ip + 2);
11926                                 klass = mini_get_class (method, token, generic_context);
11927                                 CHECK_TYPELOAD (klass);
11928                                 if (generic_class_is_reference_type (cfg, klass))
11929                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11930                                 else
11931                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11932                                 ip += 6;
11933                                 inline_costs += 1;
11934                                 break;
11935                         case CEE_CONSTRAINED_:
11936                                 CHECK_OPSIZE (6);
11937                                 token = read32 (ip + 2);
11938                                 constrained_call = mini_get_class (method, token, generic_context);
11939                                 CHECK_TYPELOAD (constrained_call);
11940                                 ip += 6;
11941                                 break;
11942                         case CEE_CPBLK:
11943                         case CEE_INITBLK: {
11944                                 MonoInst *iargs [3];
11945                                 CHECK_STACK (3);
11946                                 sp -= 3;
11947
11948                                 /* Skip optimized paths for volatile operations. */
11949                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11950                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11951                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (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)) {
11952                                         /* emit_memset only works when val == 0 */
11953                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11954                                 } else {
11955                                         MonoInst *call;
11956                                         iargs [0] = sp [0];
11957                                         iargs [1] = sp [1];
11958                                         iargs [2] = sp [2];
11959                                         if (ip [1] == CEE_CPBLK) {
11960                                                 /*
11961                                                  * FIXME: It's unclear whether we should be emitting both the acquire
11962                                                  * and release barriers for cpblk. It is technically both a load and
11963                                                  * store operation, so it seems like that's the sensible thing to do.
11964                                                  */
11965                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11966                                                 if (ins_flag & MONO_INST_VOLATILE) {
11967                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11968                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11969                                                         emit_memory_barrier (cfg, FullBarrier);
11970                                                 }
11971                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11972                                                 call->flags |= ins_flag;
11973                                                 if (ins_flag & MONO_INST_VOLATILE) {
11974                                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11975                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11976                                                         emit_memory_barrier (cfg, FullBarrier);
11977                                                 }
11978                                         } else {
11979                                                 MonoMethod *memset_method = get_memset_method ();
11980                                                 if (ins_flag & MONO_INST_VOLATILE) {
11981                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11982                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
11983                                                         emit_memory_barrier (cfg, FullBarrier);
11984                                                 }
11985                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
11986                                                 call->flags |= ins_flag;
11987                                         }
11988                                 }
11989                                 ip += 2;
11990                                 ins_flag = 0;
11991                                 inline_costs += 1;
11992                                 break;
11993                         }
11994                         case CEE_NO_:
11995                                 CHECK_OPSIZE (3);
11996                                 if (ip [2] & 0x1)
11997                                         ins_flag |= MONO_INST_NOTYPECHECK;
11998                                 if (ip [2] & 0x2)
11999                                         ins_flag |= MONO_INST_NORANGECHECK;
12000                                 /* we ignore the no-nullcheck for now since we
12001                                  * really do it explicitly only when doing callvirt->call
12002                                  */
12003                                 ip += 3;
12004                                 break;
12005                         case CEE_RETHROW: {
12006                                 MonoInst *load;
12007                                 int handler_offset = -1;
12008
12009                                 for (i = 0; i < header->num_clauses; ++i) {
12010                                         MonoExceptionClause *clause = &header->clauses [i];
12011                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12012                                                 handler_offset = clause->handler_offset;
12013                                                 break;
12014                                         }
12015                                 }
12016
12017                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12018
12019                                 g_assert (handler_offset != -1);
12020
12021                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12022                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12023                                 ins->sreg1 = load->dreg;
12024                                 MONO_ADD_INS (bblock, ins);
12025
12026                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12027                                 MONO_ADD_INS (bblock, ins);
12028
12029                                 sp = stack_start;
12030                                 link_bblock (cfg, bblock, end_bblock);
12031                                 start_new_bblock = 1;
12032                                 ip += 2;
12033                                 break;
12034                         }
12035                         case CEE_SIZEOF: {
12036                                 guint32 val;
12037                                 int ialign;
12038
12039                                 GSHAREDVT_FAILURE (*ip);
12040
12041                                 CHECK_STACK_OVF (1);
12042                                 CHECK_OPSIZE (6);
12043                                 token = read32 (ip + 2);
12044                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
12045                                         MonoType *type = mono_type_create_from_typespec (image, token);
12046                                         val = mono_type_size (type, &ialign);
12047                                 } else {
12048                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
12049                                         CHECK_TYPELOAD (klass);
12050                                         mono_class_init (klass);
12051                                         val = mono_type_size (&klass->byval_arg, &ialign);
12052                                 }
12053                                 EMIT_NEW_ICONST (cfg, ins, val);
12054                                 *sp++= ins;
12055                                 ip += 6;
12056                                 break;
12057                         }
12058                         case CEE_REFANYTYPE: {
12059                                 MonoInst *src_var, *src;
12060
12061                                 GSHAREDVT_FAILURE (*ip);
12062
12063                                 CHECK_STACK (1);
12064                                 --sp;
12065
12066                                 // FIXME:
12067                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12068                                 if (!src_var)
12069                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12070                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12071                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
12072                                 *sp++ = ins;
12073                                 ip += 2;
12074                                 break;
12075                         }
12076                         case CEE_READONLY_:
12077                                 readonly = TRUE;
12078                                 ip += 2;
12079                                 break;
12080
12081                         case CEE_UNUSED56:
12082                         case CEE_UNUSED57:
12083                         case CEE_UNUSED70:
12084                         case CEE_UNUSED:
12085                         case CEE_UNUSED99:
12086                                 UNVERIFIED;
12087                                 
12088                         default:
12089                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12090                                 UNVERIFIED;
12091                         }
12092                         break;
12093                 }
12094                 case CEE_UNUSED58:
12095                 case CEE_UNUSED1:
12096                         UNVERIFIED;
12097
12098                 default:
12099                         g_warning ("opcode 0x%02x not handled", *ip);
12100                         UNVERIFIED;
12101                 }
12102         }
12103         if (start_new_bblock != 1)
12104                 UNVERIFIED;
12105
12106         bblock->cil_length = ip - bblock->cil_code;
12107         if (bblock->next_bb) {
12108                 /* This could already be set because of inlining, #693905 */
12109                 MonoBasicBlock *bb = bblock;
12110
12111                 while (bb->next_bb)
12112                         bb = bb->next_bb;
12113                 bb->next_bb = end_bblock;
12114         } else {
12115                 bblock->next_bb = end_bblock;
12116         }
12117
12118         if (cfg->method == method && cfg->domainvar) {
12119                 MonoInst *store;
12120                 MonoInst *get_domain;
12121
12122                 cfg->cbb = init_localsbb;
12123
12124                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12125                         MONO_ADD_INS (cfg->cbb, get_domain);
12126                 } else {
12127                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12128                 }
12129                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12130                 MONO_ADD_INS (cfg->cbb, store);
12131         }
12132
12133 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12134         if (cfg->compile_aot)
12135                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12136                 mono_get_got_var (cfg);
12137 #endif
12138
12139         if (cfg->method == method && cfg->got_var)
12140                 mono_emit_load_got_addr (cfg);
12141
12142         if (init_localsbb) {
12143                 cfg->cbb = init_localsbb;
12144                 cfg->ip = NULL;
12145                 for (i = 0; i < header->num_locals; ++i) {
12146                         emit_init_local (cfg, i, header->locals [i], init_locals);
12147                 }
12148         }
12149
12150         if (cfg->init_ref_vars && cfg->method == method) {
12151                 /* Emit initialization for ref vars */
12152                 // FIXME: Avoid duplication initialization for IL locals.
12153                 for (i = 0; i < cfg->num_varinfo; ++i) {
12154                         MonoInst *ins = cfg->varinfo [i];
12155
12156                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12157                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12158                 }
12159         }
12160
12161         if (cfg->lmf_var && cfg->method == method) {
12162                 cfg->cbb = init_localsbb;
12163                 emit_push_lmf (cfg);
12164         }
12165
12166         if (seq_points) {
12167                 MonoBasicBlock *bb;
12168
12169                 /*
12170                  * Make seq points at backward branch targets interruptable.
12171                  */
12172                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12173                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12174                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12175         }
12176
12177         /* Add a sequence point for method entry/exit events */
12178         if (seq_points) {
12179                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12180                 MONO_ADD_INS (init_localsbb, ins);
12181                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12182                 MONO_ADD_INS (cfg->bb_exit, ins);
12183         }
12184
12185         /*
12186          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12187          * the code they refer to was dead (#11880).
12188          */
12189         if (sym_seq_points) {
12190                 for (i = 0; i < header->code_size; ++i) {
12191                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12192                                 MonoInst *ins;
12193
12194                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12195                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12196                         }
12197                 }
12198         }
12199
12200         cfg->ip = NULL;
12201
12202         if (cfg->method == method) {
12203                 MonoBasicBlock *bb;
12204                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12205                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12206                         if (cfg->spvars)
12207                                 mono_create_spvar_for_region (cfg, bb->region);
12208                         if (cfg->verbose_level > 2)
12209                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12210                 }
12211         }
12212
12213         g_slist_free (class_inits);
12214         dont_inline = g_list_remove (dont_inline, method);
12215
12216         if (inline_costs < 0) {
12217                 char *mname;
12218
12219                 /* Method is too large */
12220                 mname = mono_method_full_name (method, TRUE);
12221                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12222                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12223                 g_free (mname);
12224                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12225                 mono_basic_block_free (original_bb);
12226                 return -1;
12227         }
12228
12229         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12230                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12231
12232         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12233         mono_basic_block_free (original_bb);
12234         return inline_costs;
12235  
12236  exception_exit:
12237         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12238         goto cleanup;
12239
12240  inline_failure:
12241         goto cleanup;
12242
12243  load_error:
12244         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
12245         goto cleanup;
12246
12247  unverified:
12248         set_exception_type_from_invalid_il (cfg, method, ip);
12249         goto cleanup;
12250
12251  cleanup:
12252         g_slist_free (class_inits);
12253         mono_basic_block_free (original_bb);
12254         dont_inline = g_list_remove (dont_inline, method);
12255         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12256         return -1;
12257 }
12258
12259 static int
12260 store_membase_reg_to_store_membase_imm (int opcode)
12261 {
12262         switch (opcode) {
12263         case OP_STORE_MEMBASE_REG:
12264                 return OP_STORE_MEMBASE_IMM;
12265         case OP_STOREI1_MEMBASE_REG:
12266                 return OP_STOREI1_MEMBASE_IMM;
12267         case OP_STOREI2_MEMBASE_REG:
12268                 return OP_STOREI2_MEMBASE_IMM;
12269         case OP_STOREI4_MEMBASE_REG:
12270                 return OP_STOREI4_MEMBASE_IMM;
12271         case OP_STOREI8_MEMBASE_REG:
12272                 return OP_STOREI8_MEMBASE_IMM;
12273         default:
12274                 g_assert_not_reached ();
12275         }
12276
12277         return -1;
12278 }               
12279
12280 int
12281 mono_op_to_op_imm (int opcode)
12282 {
12283         switch (opcode) {
12284         case OP_IADD:
12285                 return OP_IADD_IMM;
12286         case OP_ISUB:
12287                 return OP_ISUB_IMM;
12288         case OP_IDIV:
12289                 return OP_IDIV_IMM;
12290         case OP_IDIV_UN:
12291                 return OP_IDIV_UN_IMM;
12292         case OP_IREM:
12293                 return OP_IREM_IMM;
12294         case OP_IREM_UN:
12295                 return OP_IREM_UN_IMM;
12296         case OP_IMUL:
12297                 return OP_IMUL_IMM;
12298         case OP_IAND:
12299                 return OP_IAND_IMM;
12300         case OP_IOR:
12301                 return OP_IOR_IMM;
12302         case OP_IXOR:
12303                 return OP_IXOR_IMM;
12304         case OP_ISHL:
12305                 return OP_ISHL_IMM;
12306         case OP_ISHR:
12307                 return OP_ISHR_IMM;
12308         case OP_ISHR_UN:
12309                 return OP_ISHR_UN_IMM;
12310
12311         case OP_LADD:
12312                 return OP_LADD_IMM;
12313         case OP_LSUB:
12314                 return OP_LSUB_IMM;
12315         case OP_LAND:
12316                 return OP_LAND_IMM;
12317         case OP_LOR:
12318                 return OP_LOR_IMM;
12319         case OP_LXOR:
12320                 return OP_LXOR_IMM;
12321         case OP_LSHL:
12322                 return OP_LSHL_IMM;
12323         case OP_LSHR:
12324                 return OP_LSHR_IMM;
12325         case OP_LSHR_UN:
12326                 return OP_LSHR_UN_IMM;          
12327
12328         case OP_COMPARE:
12329                 return OP_COMPARE_IMM;
12330         case OP_ICOMPARE:
12331                 return OP_ICOMPARE_IMM;
12332         case OP_LCOMPARE:
12333                 return OP_LCOMPARE_IMM;
12334
12335         case OP_STORE_MEMBASE_REG:
12336                 return OP_STORE_MEMBASE_IMM;
12337         case OP_STOREI1_MEMBASE_REG:
12338                 return OP_STOREI1_MEMBASE_IMM;
12339         case OP_STOREI2_MEMBASE_REG:
12340                 return OP_STOREI2_MEMBASE_IMM;
12341         case OP_STOREI4_MEMBASE_REG:
12342                 return OP_STOREI4_MEMBASE_IMM;
12343
12344 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12345         case OP_X86_PUSH:
12346                 return OP_X86_PUSH_IMM;
12347         case OP_X86_COMPARE_MEMBASE_REG:
12348                 return OP_X86_COMPARE_MEMBASE_IMM;
12349 #endif
12350 #if defined(TARGET_AMD64)
12351         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12352                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12353 #endif
12354         case OP_VOIDCALL_REG:
12355                 return OP_VOIDCALL;
12356         case OP_CALL_REG:
12357                 return OP_CALL;
12358         case OP_LCALL_REG:
12359                 return OP_LCALL;
12360         case OP_FCALL_REG:
12361                 return OP_FCALL;
12362         case OP_LOCALLOC:
12363                 return OP_LOCALLOC_IMM;
12364         }
12365
12366         return -1;
12367 }
12368
12369 static int
12370 ldind_to_load_membase (int opcode)
12371 {
12372         switch (opcode) {
12373         case CEE_LDIND_I1:
12374                 return OP_LOADI1_MEMBASE;
12375         case CEE_LDIND_U1:
12376                 return OP_LOADU1_MEMBASE;
12377         case CEE_LDIND_I2:
12378                 return OP_LOADI2_MEMBASE;
12379         case CEE_LDIND_U2:
12380                 return OP_LOADU2_MEMBASE;
12381         case CEE_LDIND_I4:
12382                 return OP_LOADI4_MEMBASE;
12383         case CEE_LDIND_U4:
12384                 return OP_LOADU4_MEMBASE;
12385         case CEE_LDIND_I:
12386                 return OP_LOAD_MEMBASE;
12387         case CEE_LDIND_REF:
12388                 return OP_LOAD_MEMBASE;
12389         case CEE_LDIND_I8:
12390                 return OP_LOADI8_MEMBASE;
12391         case CEE_LDIND_R4:
12392                 return OP_LOADR4_MEMBASE;
12393         case CEE_LDIND_R8:
12394                 return OP_LOADR8_MEMBASE;
12395         default:
12396                 g_assert_not_reached ();
12397         }
12398
12399         return -1;
12400 }
12401
12402 static int
12403 stind_to_store_membase (int opcode)
12404 {
12405         switch (opcode) {
12406         case CEE_STIND_I1:
12407                 return OP_STOREI1_MEMBASE_REG;
12408         case CEE_STIND_I2:
12409                 return OP_STOREI2_MEMBASE_REG;
12410         case CEE_STIND_I4:
12411                 return OP_STOREI4_MEMBASE_REG;
12412         case CEE_STIND_I:
12413         case CEE_STIND_REF:
12414                 return OP_STORE_MEMBASE_REG;
12415         case CEE_STIND_I8:
12416                 return OP_STOREI8_MEMBASE_REG;
12417         case CEE_STIND_R4:
12418                 return OP_STORER4_MEMBASE_REG;
12419         case CEE_STIND_R8:
12420                 return OP_STORER8_MEMBASE_REG;
12421         default:
12422                 g_assert_not_reached ();
12423         }
12424
12425         return -1;
12426 }
12427
12428 int
12429 mono_load_membase_to_load_mem (int opcode)
12430 {
12431         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12432 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12433         switch (opcode) {
12434         case OP_LOAD_MEMBASE:
12435                 return OP_LOAD_MEM;
12436         case OP_LOADU1_MEMBASE:
12437                 return OP_LOADU1_MEM;
12438         case OP_LOADU2_MEMBASE:
12439                 return OP_LOADU2_MEM;
12440         case OP_LOADI4_MEMBASE:
12441                 return OP_LOADI4_MEM;
12442         case OP_LOADU4_MEMBASE:
12443                 return OP_LOADU4_MEM;
12444 #if SIZEOF_REGISTER == 8
12445         case OP_LOADI8_MEMBASE:
12446                 return OP_LOADI8_MEM;
12447 #endif
12448         }
12449 #endif
12450
12451         return -1;
12452 }
12453
12454 static inline int
12455 op_to_op_dest_membase (int store_opcode, int opcode)
12456 {
12457 #if defined(TARGET_X86)
12458         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12459                 return -1;
12460
12461         switch (opcode) {
12462         case OP_IADD:
12463                 return OP_X86_ADD_MEMBASE_REG;
12464         case OP_ISUB:
12465                 return OP_X86_SUB_MEMBASE_REG;
12466         case OP_IAND:
12467                 return OP_X86_AND_MEMBASE_REG;
12468         case OP_IOR:
12469                 return OP_X86_OR_MEMBASE_REG;
12470         case OP_IXOR:
12471                 return OP_X86_XOR_MEMBASE_REG;
12472         case OP_ADD_IMM:
12473         case OP_IADD_IMM:
12474                 return OP_X86_ADD_MEMBASE_IMM;
12475         case OP_SUB_IMM:
12476         case OP_ISUB_IMM:
12477                 return OP_X86_SUB_MEMBASE_IMM;
12478         case OP_AND_IMM:
12479         case OP_IAND_IMM:
12480                 return OP_X86_AND_MEMBASE_IMM;
12481         case OP_OR_IMM:
12482         case OP_IOR_IMM:
12483                 return OP_X86_OR_MEMBASE_IMM;
12484         case OP_XOR_IMM:
12485         case OP_IXOR_IMM:
12486                 return OP_X86_XOR_MEMBASE_IMM;
12487         case OP_MOVE:
12488                 return OP_NOP;
12489         }
12490 #endif
12491
12492 #if defined(TARGET_AMD64)
12493         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12494                 return -1;
12495
12496         switch (opcode) {
12497         case OP_IADD:
12498                 return OP_X86_ADD_MEMBASE_REG;
12499         case OP_ISUB:
12500                 return OP_X86_SUB_MEMBASE_REG;
12501         case OP_IAND:
12502                 return OP_X86_AND_MEMBASE_REG;
12503         case OP_IOR:
12504                 return OP_X86_OR_MEMBASE_REG;
12505         case OP_IXOR:
12506                 return OP_X86_XOR_MEMBASE_REG;
12507         case OP_IADD_IMM:
12508                 return OP_X86_ADD_MEMBASE_IMM;
12509         case OP_ISUB_IMM:
12510                 return OP_X86_SUB_MEMBASE_IMM;
12511         case OP_IAND_IMM:
12512                 return OP_X86_AND_MEMBASE_IMM;
12513         case OP_IOR_IMM:
12514                 return OP_X86_OR_MEMBASE_IMM;
12515         case OP_IXOR_IMM:
12516                 return OP_X86_XOR_MEMBASE_IMM;
12517         case OP_LADD:
12518                 return OP_AMD64_ADD_MEMBASE_REG;
12519         case OP_LSUB:
12520                 return OP_AMD64_SUB_MEMBASE_REG;
12521         case OP_LAND:
12522                 return OP_AMD64_AND_MEMBASE_REG;
12523         case OP_LOR:
12524                 return OP_AMD64_OR_MEMBASE_REG;
12525         case OP_LXOR:
12526                 return OP_AMD64_XOR_MEMBASE_REG;
12527         case OP_ADD_IMM:
12528         case OP_LADD_IMM:
12529                 return OP_AMD64_ADD_MEMBASE_IMM;
12530         case OP_SUB_IMM:
12531         case OP_LSUB_IMM:
12532                 return OP_AMD64_SUB_MEMBASE_IMM;
12533         case OP_AND_IMM:
12534         case OP_LAND_IMM:
12535                 return OP_AMD64_AND_MEMBASE_IMM;
12536         case OP_OR_IMM:
12537         case OP_LOR_IMM:
12538                 return OP_AMD64_OR_MEMBASE_IMM;
12539         case OP_XOR_IMM:
12540         case OP_LXOR_IMM:
12541                 return OP_AMD64_XOR_MEMBASE_IMM;
12542         case OP_MOVE:
12543                 return OP_NOP;
12544         }
12545 #endif
12546
12547         return -1;
12548 }
12549
12550 static inline int
12551 op_to_op_store_membase (int store_opcode, int opcode)
12552 {
12553 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12554         switch (opcode) {
12555         case OP_ICEQ:
12556                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12557                         return OP_X86_SETEQ_MEMBASE;
12558         case OP_CNE:
12559                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12560                         return OP_X86_SETNE_MEMBASE;
12561         }
12562 #endif
12563
12564         return -1;
12565 }
12566
12567 static inline int
12568 op_to_op_src1_membase (int load_opcode, int opcode)
12569 {
12570 #ifdef TARGET_X86
12571         /* FIXME: This has sign extension issues */
12572         /*
12573         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12574                 return OP_X86_COMPARE_MEMBASE8_IMM;
12575         */
12576
12577         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12578                 return -1;
12579
12580         switch (opcode) {
12581         case OP_X86_PUSH:
12582                 return OP_X86_PUSH_MEMBASE;
12583         case OP_COMPARE_IMM:
12584         case OP_ICOMPARE_IMM:
12585                 return OP_X86_COMPARE_MEMBASE_IMM;
12586         case OP_COMPARE:
12587         case OP_ICOMPARE:
12588                 return OP_X86_COMPARE_MEMBASE_REG;
12589         }
12590 #endif
12591
12592 #ifdef TARGET_AMD64
12593         /* FIXME: This has sign extension issues */
12594         /*
12595         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12596                 return OP_X86_COMPARE_MEMBASE8_IMM;
12597         */
12598
12599         switch (opcode) {
12600         case OP_X86_PUSH:
12601 #ifdef __mono_ilp32__
12602                 if (load_opcode == OP_LOADI8_MEMBASE)
12603 #else
12604                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12605 #endif
12606                         return OP_X86_PUSH_MEMBASE;
12607                 break;
12608                 /* FIXME: This only works for 32 bit immediates
12609         case OP_COMPARE_IMM:
12610         case OP_LCOMPARE_IMM:
12611                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12612                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12613                 */
12614         case OP_ICOMPARE_IMM:
12615                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12616                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12617                 break;
12618         case OP_COMPARE:
12619         case OP_LCOMPARE:
12620 #ifdef __mono_ilp32__
12621                 if (load_opcode == OP_LOAD_MEMBASE)
12622                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12623                 if (load_opcode == OP_LOADI8_MEMBASE)
12624 #else
12625                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12626 #endif
12627                         return OP_AMD64_COMPARE_MEMBASE_REG;
12628                 break;
12629         case OP_ICOMPARE:
12630                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12631                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12632                 break;
12633         }
12634 #endif
12635
12636         return -1;
12637 }
12638
12639 static inline int
12640 op_to_op_src2_membase (int load_opcode, int opcode)
12641 {
12642 #ifdef TARGET_X86
12643         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12644                 return -1;
12645         
12646         switch (opcode) {
12647         case OP_COMPARE:
12648         case OP_ICOMPARE:
12649                 return OP_X86_COMPARE_REG_MEMBASE;
12650         case OP_IADD:
12651                 return OP_X86_ADD_REG_MEMBASE;
12652         case OP_ISUB:
12653                 return OP_X86_SUB_REG_MEMBASE;
12654         case OP_IAND:
12655                 return OP_X86_AND_REG_MEMBASE;
12656         case OP_IOR:
12657                 return OP_X86_OR_REG_MEMBASE;
12658         case OP_IXOR:
12659                 return OP_X86_XOR_REG_MEMBASE;
12660         }
12661 #endif
12662
12663 #ifdef TARGET_AMD64
12664 #ifdef __mono_ilp32__
12665         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12666 #else
12667         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12668 #endif
12669                 switch (opcode) {
12670                 case OP_ICOMPARE:
12671                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12672                 case OP_IADD:
12673                         return OP_X86_ADD_REG_MEMBASE;
12674                 case OP_ISUB:
12675                         return OP_X86_SUB_REG_MEMBASE;
12676                 case OP_IAND:
12677                         return OP_X86_AND_REG_MEMBASE;
12678                 case OP_IOR:
12679                         return OP_X86_OR_REG_MEMBASE;
12680                 case OP_IXOR:
12681                         return OP_X86_XOR_REG_MEMBASE;
12682                 }
12683 #ifdef __mono_ilp32__
12684         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12685 #else
12686         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12687 #endif
12688                 switch (opcode) {
12689                 case OP_COMPARE:
12690                 case OP_LCOMPARE:
12691                         return OP_AMD64_COMPARE_REG_MEMBASE;
12692                 case OP_LADD:
12693                         return OP_AMD64_ADD_REG_MEMBASE;
12694                 case OP_LSUB:
12695                         return OP_AMD64_SUB_REG_MEMBASE;
12696                 case OP_LAND:
12697                         return OP_AMD64_AND_REG_MEMBASE;
12698                 case OP_LOR:
12699                         return OP_AMD64_OR_REG_MEMBASE;
12700                 case OP_LXOR:
12701                         return OP_AMD64_XOR_REG_MEMBASE;
12702                 }
12703         }
12704 #endif
12705
12706         return -1;
12707 }
12708
12709 int
12710 mono_op_to_op_imm_noemul (int opcode)
12711 {
12712         switch (opcode) {
12713 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12714         case OP_LSHR:
12715         case OP_LSHL:
12716         case OP_LSHR_UN:
12717                 return -1;
12718 #endif
12719 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12720         case OP_IDIV:
12721         case OP_IDIV_UN:
12722         case OP_IREM:
12723         case OP_IREM_UN:
12724                 return -1;
12725 #endif
12726 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12727         case OP_IMUL:
12728                 return -1;
12729 #endif
12730         default:
12731                 return mono_op_to_op_imm (opcode);
12732         }
12733 }
12734
12735 /**
12736  * mono_handle_global_vregs:
12737  *
12738  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12739  * for them.
12740  */
12741 void
12742 mono_handle_global_vregs (MonoCompile *cfg)
12743 {
12744         gint32 *vreg_to_bb;
12745         MonoBasicBlock *bb;
12746         int i, pos;
12747
12748         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12749
12750 #ifdef MONO_ARCH_SIMD_INTRINSICS
12751         if (cfg->uses_simd_intrinsics)
12752                 mono_simd_simplify_indirection (cfg);
12753 #endif
12754
12755         /* Find local vregs used in more than one bb */
12756         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12757                 MonoInst *ins = bb->code;       
12758                 int block_num = bb->block_num;
12759
12760                 if (cfg->verbose_level > 2)
12761                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12762
12763                 cfg->cbb = bb;
12764                 for (; ins; ins = ins->next) {
12765                         const char *spec = INS_INFO (ins->opcode);
12766                         int regtype = 0, regindex;
12767                         gint32 prev_bb;
12768
12769                         if (G_UNLIKELY (cfg->verbose_level > 2))
12770                                 mono_print_ins (ins);
12771
12772                         g_assert (ins->opcode >= MONO_CEE_LAST);
12773
12774                         for (regindex = 0; regindex < 4; regindex ++) {
12775                                 int vreg = 0;
12776
12777                                 if (regindex == 0) {
12778                                         regtype = spec [MONO_INST_DEST];
12779                                         if (regtype == ' ')
12780                                                 continue;
12781                                         vreg = ins->dreg;
12782                                 } else if (regindex == 1) {
12783                                         regtype = spec [MONO_INST_SRC1];
12784                                         if (regtype == ' ')
12785                                                 continue;
12786                                         vreg = ins->sreg1;
12787                                 } else if (regindex == 2) {
12788                                         regtype = spec [MONO_INST_SRC2];
12789                                         if (regtype == ' ')
12790                                                 continue;
12791                                         vreg = ins->sreg2;
12792                                 } else if (regindex == 3) {
12793                                         regtype = spec [MONO_INST_SRC3];
12794                                         if (regtype == ' ')
12795                                                 continue;
12796                                         vreg = ins->sreg3;
12797                                 }
12798
12799 #if SIZEOF_REGISTER == 4
12800                                 /* In the LLVM case, the long opcodes are not decomposed */
12801                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12802                                         /*
12803                                          * Since some instructions reference the original long vreg,
12804                                          * and some reference the two component vregs, it is quite hard
12805                                          * to determine when it needs to be global. So be conservative.
12806                                          */
12807                                         if (!get_vreg_to_inst (cfg, vreg)) {
12808                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12809
12810                                                 if (cfg->verbose_level > 2)
12811                                                         printf ("LONG VREG R%d made global.\n", vreg);
12812                                         }
12813
12814                                         /*
12815                                          * Make the component vregs volatile since the optimizations can
12816                                          * get confused otherwise.
12817                                          */
12818                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12819                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12820                                 }
12821 #endif
12822
12823                                 g_assert (vreg != -1);
12824
12825                                 prev_bb = vreg_to_bb [vreg];
12826                                 if (prev_bb == 0) {
12827                                         /* 0 is a valid block num */
12828                                         vreg_to_bb [vreg] = block_num + 1;
12829                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12830                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12831                                                 continue;
12832
12833                                         if (!get_vreg_to_inst (cfg, vreg)) {
12834                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12835                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12836
12837                                                 switch (regtype) {
12838                                                 case 'i':
12839                                                         if (vreg_is_ref (cfg, vreg))
12840                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12841                                                         else
12842                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12843                                                         break;
12844                                                 case 'l':
12845                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12846                                                         break;
12847                                                 case 'f':
12848                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12849                                                         break;
12850                                                 case 'v':
12851                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12852                                                         break;
12853                                                 default:
12854                                                         g_assert_not_reached ();
12855                                                 }
12856                                         }
12857
12858                                         /* Flag as having been used in more than one bb */
12859                                         vreg_to_bb [vreg] = -1;
12860                                 }
12861                         }
12862                 }
12863         }
12864
12865         /* If a variable is used in only one bblock, convert it into a local vreg */
12866         for (i = 0; i < cfg->num_varinfo; i++) {
12867                 MonoInst *var = cfg->varinfo [i];
12868                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12869
12870                 switch (var->type) {
12871                 case STACK_I4:
12872                 case STACK_OBJ:
12873                 case STACK_PTR:
12874                 case STACK_MP:
12875                 case STACK_VTYPE:
12876 #if SIZEOF_REGISTER == 8
12877                 case STACK_I8:
12878 #endif
12879 #if !defined(TARGET_X86)
12880                 /* Enabling this screws up the fp stack on x86 */
12881                 case STACK_R8:
12882 #endif
12883                         if (mono_arch_is_soft_float ())
12884                                 break;
12885
12886                         /* Arguments are implicitly global */
12887                         /* Putting R4 vars into registers doesn't work currently */
12888                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12889                         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) {
12890                                 /* 
12891                                  * Make that the variable's liveness interval doesn't contain a call, since
12892                                  * that would cause the lvreg to be spilled, making the whole optimization
12893                                  * useless.
12894                                  */
12895                                 /* This is too slow for JIT compilation */
12896 #if 0
12897                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12898                                         MonoInst *ins;
12899                                         int def_index, call_index, ins_index;
12900                                         gboolean spilled = FALSE;
12901
12902                                         def_index = -1;
12903                                         call_index = -1;
12904                                         ins_index = 0;
12905                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12906                                                 const char *spec = INS_INFO (ins->opcode);
12907
12908                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12909                                                         def_index = ins_index;
12910
12911                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12912                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12913                                                         if (call_index > def_index) {
12914                                                                 spilled = TRUE;
12915                                                                 break;
12916                                                         }
12917                                                 }
12918
12919                                                 if (MONO_IS_CALL (ins))
12920                                                         call_index = ins_index;
12921
12922                                                 ins_index ++;
12923                                         }
12924
12925                                         if (spilled)
12926                                                 break;
12927                                 }
12928 #endif
12929
12930                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12931                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12932                                 var->flags |= MONO_INST_IS_DEAD;
12933                                 cfg->vreg_to_inst [var->dreg] = NULL;
12934                         }
12935                         break;
12936                 }
12937         }
12938
12939         /* 
12940          * Compress the varinfo and vars tables so the liveness computation is faster and
12941          * takes up less space.
12942          */
12943         pos = 0;
12944         for (i = 0; i < cfg->num_varinfo; ++i) {
12945                 MonoInst *var = cfg->varinfo [i];
12946                 if (pos < i && cfg->locals_start == i)
12947                         cfg->locals_start = pos;
12948                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12949                         if (pos < i) {
12950                                 cfg->varinfo [pos] = cfg->varinfo [i];
12951                                 cfg->varinfo [pos]->inst_c0 = pos;
12952                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12953                                 cfg->vars [pos].idx = pos;
12954 #if SIZEOF_REGISTER == 4
12955                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12956                                         /* Modify the two component vars too */
12957                                         MonoInst *var1;
12958
12959                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12960                                         var1->inst_c0 = pos;
12961                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12962                                         var1->inst_c0 = pos;
12963                                 }
12964 #endif
12965                         }
12966                         pos ++;
12967                 }
12968         }
12969         cfg->num_varinfo = pos;
12970         if (cfg->locals_start > cfg->num_varinfo)
12971                 cfg->locals_start = cfg->num_varinfo;
12972 }
12973
12974 /**
12975  * mono_spill_global_vars:
12976  *
12977  *   Generate spill code for variables which are not allocated to registers, 
12978  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12979  * code is generated which could be optimized by the local optimization passes.
12980  */
12981 void
12982 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12983 {
12984         MonoBasicBlock *bb;
12985         char spec2 [16];
12986         int orig_next_vreg;
12987         guint32 *vreg_to_lvreg;
12988         guint32 *lvregs;
12989         guint32 i, lvregs_len;
12990         gboolean dest_has_lvreg = FALSE;
12991         guint32 stacktypes [128];
12992         MonoInst **live_range_start, **live_range_end;
12993         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12994         int *gsharedvt_vreg_to_idx = NULL;
12995
12996         *need_local_opts = FALSE;
12997
12998         memset (spec2, 0, sizeof (spec2));
12999
13000         /* FIXME: Move this function to mini.c */
13001         stacktypes ['i'] = STACK_PTR;
13002         stacktypes ['l'] = STACK_I8;
13003         stacktypes ['f'] = STACK_R8;
13004 #ifdef MONO_ARCH_SIMD_INTRINSICS
13005         stacktypes ['x'] = STACK_VTYPE;
13006 #endif
13007
13008 #if SIZEOF_REGISTER == 4
13009         /* Create MonoInsts for longs */
13010         for (i = 0; i < cfg->num_varinfo; i++) {
13011                 MonoInst *ins = cfg->varinfo [i];
13012
13013                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13014                         switch (ins->type) {
13015                         case STACK_R8:
13016                         case STACK_I8: {
13017                                 MonoInst *tree;
13018
13019                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13020                                         break;
13021
13022                                 g_assert (ins->opcode == OP_REGOFFSET);
13023
13024                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13025                                 g_assert (tree);
13026                                 tree->opcode = OP_REGOFFSET;
13027                                 tree->inst_basereg = ins->inst_basereg;
13028                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13029
13030                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13031                                 g_assert (tree);
13032                                 tree->opcode = OP_REGOFFSET;
13033                                 tree->inst_basereg = ins->inst_basereg;
13034                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13035                                 break;
13036                         }
13037                         default:
13038                                 break;
13039                         }
13040                 }
13041         }
13042 #endif
13043
13044         if (cfg->compute_gc_maps) {
13045                 /* registers need liveness info even for !non refs */
13046                 for (i = 0; i < cfg->num_varinfo; i++) {
13047                         MonoInst *ins = cfg->varinfo [i];
13048
13049                         if (ins->opcode == OP_REGVAR)
13050                                 ins->flags |= MONO_INST_GC_TRACK;
13051                 }
13052         }
13053
13054         if (cfg->gsharedvt) {
13055                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13056
13057                 for (i = 0; i < cfg->num_varinfo; ++i) {
13058                         MonoInst *ins = cfg->varinfo [i];
13059                         int idx;
13060
13061                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13062                                 if (i >= cfg->locals_start) {
13063                                         /* Local */
13064                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13065                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13066                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13067                                         ins->inst_imm = idx;
13068                                 } else {
13069                                         /* Arg */
13070                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13071                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13072                                 }
13073                         }
13074                 }
13075         }
13076                 
13077         /* FIXME: widening and truncation */
13078
13079         /*
13080          * As an optimization, when a variable allocated to the stack is first loaded into 
13081          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13082          * the variable again.
13083          */
13084         orig_next_vreg = cfg->next_vreg;
13085         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13086         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13087         lvregs_len = 0;
13088
13089         /* 
13090          * These arrays contain the first and last instructions accessing a given
13091          * variable.
13092          * Since we emit bblocks in the same order we process them here, and we
13093          * don't split live ranges, these will precisely describe the live range of
13094          * the variable, i.e. the instruction range where a valid value can be found
13095          * in the variables location.
13096          * The live range is computed using the liveness info computed by the liveness pass.
13097          * We can't use vmv->range, since that is an abstract live range, and we need
13098          * one which is instruction precise.
13099          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13100          */
13101         /* FIXME: Only do this if debugging info is requested */
13102         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13103         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13104         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13105         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13106         
13107         /* Add spill loads/stores */
13108         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13109                 MonoInst *ins;
13110
13111                 if (cfg->verbose_level > 2)
13112                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13113
13114                 /* Clear vreg_to_lvreg array */
13115                 for (i = 0; i < lvregs_len; i++)
13116                         vreg_to_lvreg [lvregs [i]] = 0;
13117                 lvregs_len = 0;
13118
13119                 cfg->cbb = bb;
13120                 MONO_BB_FOR_EACH_INS (bb, ins) {
13121                         const char *spec = INS_INFO (ins->opcode);
13122                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13123                         gboolean store, no_lvreg;
13124                         int sregs [MONO_MAX_SRC_REGS];
13125
13126                         if (G_UNLIKELY (cfg->verbose_level > 2))
13127                                 mono_print_ins (ins);
13128
13129                         if (ins->opcode == OP_NOP)
13130                                 continue;
13131
13132                         /* 
13133                          * We handle LDADDR here as well, since it can only be decomposed
13134                          * when variable addresses are known.
13135                          */
13136                         if (ins->opcode == OP_LDADDR) {
13137                                 MonoInst *var = ins->inst_p0;
13138
13139                                 if (var->opcode == OP_VTARG_ADDR) {
13140                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13141                                         MonoInst *vtaddr = var->inst_left;
13142                                         if (vtaddr->opcode == OP_REGVAR) {
13143                                                 ins->opcode = OP_MOVE;
13144                                                 ins->sreg1 = vtaddr->dreg;
13145                                         }
13146                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13147                                                 ins->opcode = OP_LOAD_MEMBASE;
13148                                                 ins->inst_basereg = vtaddr->inst_basereg;
13149                                                 ins->inst_offset = vtaddr->inst_offset;
13150                                         } else
13151                                                 NOT_IMPLEMENTED;
13152                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13153                                         /* gsharedvt arg passed by ref */
13154                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13155
13156                                         ins->opcode = OP_LOAD_MEMBASE;
13157                                         ins->inst_basereg = var->inst_basereg;
13158                                         ins->inst_offset = var->inst_offset;
13159                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13160                                         MonoInst *load, *load2, *load3;
13161                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13162                                         int reg1, reg2, reg3;
13163                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13164                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13165
13166                                         /*
13167                                          * gsharedvt local.
13168                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13169                                          */
13170
13171                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13172
13173                                         g_assert (info_var);
13174                                         g_assert (locals_var);
13175
13176                                         /* Mark the instruction used to compute the locals var as used */
13177                                         cfg->gsharedvt_locals_var_ins = NULL;
13178
13179                                         /* Load the offset */
13180                                         if (info_var->opcode == OP_REGOFFSET) {
13181                                                 reg1 = alloc_ireg (cfg);
13182                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13183                                         } else if (info_var->opcode == OP_REGVAR) {
13184                                                 load = NULL;
13185                                                 reg1 = info_var->dreg;
13186                                         } else {
13187                                                 g_assert_not_reached ();
13188                                         }
13189                                         reg2 = alloc_ireg (cfg);
13190                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13191                                         /* Load the locals area address */
13192                                         reg3 = alloc_ireg (cfg);
13193                                         if (locals_var->opcode == OP_REGOFFSET) {
13194                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13195                                         } else if (locals_var->opcode == OP_REGVAR) {
13196                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13197                                         } else {
13198                                                 g_assert_not_reached ();
13199                                         }
13200                                         /* Compute the address */
13201                                         ins->opcode = OP_PADD;
13202                                         ins->sreg1 = reg3;
13203                                         ins->sreg2 = reg2;
13204
13205                                         mono_bblock_insert_before_ins (bb, ins, load3);
13206                                         mono_bblock_insert_before_ins (bb, load3, load2);
13207                                         if (load)
13208                                                 mono_bblock_insert_before_ins (bb, load2, load);
13209                                 } else {
13210                                         g_assert (var->opcode == OP_REGOFFSET);
13211
13212                                         ins->opcode = OP_ADD_IMM;
13213                                         ins->sreg1 = var->inst_basereg;
13214                                         ins->inst_imm = var->inst_offset;
13215                                 }
13216
13217                                 *need_local_opts = TRUE;
13218                                 spec = INS_INFO (ins->opcode);
13219                         }
13220
13221                         if (ins->opcode < MONO_CEE_LAST) {
13222                                 mono_print_ins (ins);
13223                                 g_assert_not_reached ();
13224                         }
13225
13226                         /*
13227                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13228                          * src register.
13229                          * FIXME:
13230                          */
13231                         if (MONO_IS_STORE_MEMBASE (ins)) {
13232                                 tmp_reg = ins->dreg;
13233                                 ins->dreg = ins->sreg2;
13234                                 ins->sreg2 = tmp_reg;
13235                                 store = TRUE;
13236
13237                                 spec2 [MONO_INST_DEST] = ' ';
13238                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13239                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13240                                 spec2 [MONO_INST_SRC3] = ' ';
13241                                 spec = spec2;
13242                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13243                                 g_assert_not_reached ();
13244                         else
13245                                 store = FALSE;
13246                         no_lvreg = FALSE;
13247
13248                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13249                                 printf ("\t %.3s %d", spec, ins->dreg);
13250                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13251                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13252                                         printf (" %d", sregs [srcindex]);
13253                                 printf ("\n");
13254                         }
13255
13256                         /***************/
13257                         /*    DREG     */
13258                         /***************/
13259                         regtype = spec [MONO_INST_DEST];
13260                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13261                         prev_dreg = -1;
13262
13263                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13264                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13265                                 MonoInst *store_ins;
13266                                 int store_opcode;
13267                                 MonoInst *def_ins = ins;
13268                                 int dreg = ins->dreg; /* The original vreg */
13269
13270                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13271
13272                                 if (var->opcode == OP_REGVAR) {
13273                                         ins->dreg = var->dreg;
13274                                 } 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)) {
13275                                         /* 
13276                                          * Instead of emitting a load+store, use a _membase opcode.
13277                                          */
13278                                         g_assert (var->opcode == OP_REGOFFSET);
13279                                         if (ins->opcode == OP_MOVE) {
13280                                                 NULLIFY_INS (ins);
13281                                                 def_ins = NULL;
13282                                         } else {
13283                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13284                                                 ins->inst_basereg = var->inst_basereg;
13285                                                 ins->inst_offset = var->inst_offset;
13286                                                 ins->dreg = -1;
13287                                         }
13288                                         spec = INS_INFO (ins->opcode);
13289                                 } else {
13290                                         guint32 lvreg;
13291
13292                                         g_assert (var->opcode == OP_REGOFFSET);
13293
13294                                         prev_dreg = ins->dreg;
13295
13296                                         /* Invalidate any previous lvreg for this vreg */
13297                                         vreg_to_lvreg [ins->dreg] = 0;
13298
13299                                         lvreg = 0;
13300
13301                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13302                                                 regtype = 'l';
13303                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13304                                         }
13305
13306                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13307
13308 #if SIZEOF_REGISTER != 8
13309                                         if (regtype == 'l') {
13310                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13311                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13312                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13313                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13314                                                 def_ins = store_ins;
13315                                         }
13316                                         else
13317 #endif
13318                                         {
13319                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13320
13321                                                 /* Try to fuse the store into the instruction itself */
13322                                                 /* FIXME: Add more instructions */
13323                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13324                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13325                                                         ins->inst_imm = ins->inst_c0;
13326                                                         ins->inst_destbasereg = var->inst_basereg;
13327                                                         ins->inst_offset = var->inst_offset;
13328                                                         spec = INS_INFO (ins->opcode);
13329                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13330                                                         ins->opcode = store_opcode;
13331                                                         ins->inst_destbasereg = var->inst_basereg;
13332                                                         ins->inst_offset = var->inst_offset;
13333
13334                                                         no_lvreg = TRUE;
13335
13336                                                         tmp_reg = ins->dreg;
13337                                                         ins->dreg = ins->sreg2;
13338                                                         ins->sreg2 = tmp_reg;
13339                                                         store = TRUE;
13340
13341                                                         spec2 [MONO_INST_DEST] = ' ';
13342                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13343                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13344                                                         spec2 [MONO_INST_SRC3] = ' ';
13345                                                         spec = spec2;
13346                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13347                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13348                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13349                                                         ins->dreg = -1;
13350                                                         ins->inst_basereg = var->inst_basereg;
13351                                                         ins->inst_offset = var->inst_offset;
13352                                                         spec = INS_INFO (ins->opcode);
13353                                                 } else {
13354                                                         /* printf ("INS: "); mono_print_ins (ins); */
13355                                                         /* Create a store instruction */
13356                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13357
13358                                                         /* Insert it after the instruction */
13359                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13360
13361                                                         def_ins = store_ins;
13362
13363                                                         /* 
13364                                                          * We can't assign ins->dreg to var->dreg here, since the
13365                                                          * sregs could use it. So set a flag, and do it after
13366                                                          * the sregs.
13367                                                          */
13368                                                         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)))
13369                                                                 dest_has_lvreg = TRUE;
13370                                                 }
13371                                         }
13372                                 }
13373
13374                                 if (def_ins && !live_range_start [dreg]) {
13375                                         live_range_start [dreg] = def_ins;
13376                                         live_range_start_bb [dreg] = bb;
13377                                 }
13378
13379                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13380                                         MonoInst *tmp;
13381
13382                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13383                                         tmp->inst_c1 = dreg;
13384                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13385                                 }
13386                         }
13387
13388                         /************/
13389                         /*  SREGS   */
13390                         /************/
13391                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13392                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13393                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13394                                 sreg = sregs [srcindex];
13395
13396                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13397                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13398                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13399                                         MonoInst *use_ins = ins;
13400                                         MonoInst *load_ins;
13401                                         guint32 load_opcode;
13402
13403                                         if (var->opcode == OP_REGVAR) {
13404                                                 sregs [srcindex] = var->dreg;
13405                                                 //mono_inst_set_src_registers (ins, sregs);
13406                                                 live_range_end [sreg] = use_ins;
13407                                                 live_range_end_bb [sreg] = bb;
13408
13409                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13410                                                         MonoInst *tmp;
13411
13412                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13413                                                         /* var->dreg is a hreg */
13414                                                         tmp->inst_c1 = sreg;
13415                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13416                                                 }
13417
13418                                                 continue;
13419                                         }
13420
13421                                         g_assert (var->opcode == OP_REGOFFSET);
13422                                                 
13423                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13424
13425                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13426
13427                                         if (vreg_to_lvreg [sreg]) {
13428                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13429
13430                                                 /* The variable is already loaded to an lvreg */
13431                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13432                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13433                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13434                                                 //mono_inst_set_src_registers (ins, sregs);
13435                                                 continue;
13436                                         }
13437
13438                                         /* Try to fuse the load into the instruction */
13439                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13440                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13441                                                 sregs [0] = var->inst_basereg;
13442                                                 //mono_inst_set_src_registers (ins, sregs);
13443                                                 ins->inst_offset = var->inst_offset;
13444                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13445                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13446                                                 sregs [1] = var->inst_basereg;
13447                                                 //mono_inst_set_src_registers (ins, sregs);
13448                                                 ins->inst_offset = var->inst_offset;
13449                                         } else {
13450                                                 if (MONO_IS_REAL_MOVE (ins)) {
13451                                                         ins->opcode = OP_NOP;
13452                                                         sreg = ins->dreg;
13453                                                 } else {
13454                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13455
13456                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13457
13458                                                         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) {
13459                                                                 if (var->dreg == prev_dreg) {
13460                                                                         /*
13461                                                                          * sreg refers to the value loaded by the load
13462                                                                          * emitted below, but we need to use ins->dreg
13463                                                                          * since it refers to the store emitted earlier.
13464                                                                          */
13465                                                                         sreg = ins->dreg;
13466                                                                 }
13467                                                                 g_assert (sreg != -1);
13468                                                                 vreg_to_lvreg [var->dreg] = sreg;
13469                                                                 g_assert (lvregs_len < 1024);
13470                                                                 lvregs [lvregs_len ++] = var->dreg;
13471                                                         }
13472                                                 }
13473
13474                                                 sregs [srcindex] = sreg;
13475                                                 //mono_inst_set_src_registers (ins, sregs);
13476
13477 #if SIZEOF_REGISTER != 8
13478                                                 if (regtype == 'l') {
13479                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13480                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13481                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13482                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13483                                                         use_ins = load_ins;
13484                                                 }
13485                                                 else
13486 #endif
13487                                                 {
13488 #if SIZEOF_REGISTER == 4
13489                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13490 #endif
13491                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13492                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13493                                                         use_ins = load_ins;
13494                                                 }
13495                                         }
13496
13497                                         if (var->dreg < orig_next_vreg) {
13498                                                 live_range_end [var->dreg] = use_ins;
13499                                                 live_range_end_bb [var->dreg] = bb;
13500                                         }
13501
13502                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13503                                                 MonoInst *tmp;
13504
13505                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13506                                                 tmp->inst_c1 = var->dreg;
13507                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13508                                         }
13509                                 }
13510                         }
13511                         mono_inst_set_src_registers (ins, sregs);
13512
13513                         if (dest_has_lvreg) {
13514                                 g_assert (ins->dreg != -1);
13515                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13516                                 g_assert (lvregs_len < 1024);
13517                                 lvregs [lvregs_len ++] = prev_dreg;
13518                                 dest_has_lvreg = FALSE;
13519                         }
13520
13521                         if (store) {
13522                                 tmp_reg = ins->dreg;
13523                                 ins->dreg = ins->sreg2;
13524                                 ins->sreg2 = tmp_reg;
13525                         }
13526
13527                         if (MONO_IS_CALL (ins)) {
13528                                 /* Clear vreg_to_lvreg array */
13529                                 for (i = 0; i < lvregs_len; i++)
13530                                         vreg_to_lvreg [lvregs [i]] = 0;
13531                                 lvregs_len = 0;
13532                         } else if (ins->opcode == OP_NOP) {
13533                                 ins->dreg = -1;
13534                                 MONO_INST_NULLIFY_SREGS (ins);
13535                         }
13536
13537                         if (cfg->verbose_level > 2)
13538                                 mono_print_ins_index (1, ins);
13539                 }
13540
13541                 /* Extend the live range based on the liveness info */
13542                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13543                         for (i = 0; i < cfg->num_varinfo; i ++) {
13544                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13545
13546                                 if (vreg_is_volatile (cfg, vi->vreg))
13547                                         /* The liveness info is incomplete */
13548                                         continue;
13549
13550                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13551                                         /* Live from at least the first ins of this bb */
13552                                         live_range_start [vi->vreg] = bb->code;
13553                                         live_range_start_bb [vi->vreg] = bb;
13554                                 }
13555
13556                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13557                                         /* Live at least until the last ins of this bb */
13558                                         live_range_end [vi->vreg] = bb->last_ins;
13559                                         live_range_end_bb [vi->vreg] = bb;
13560                                 }
13561                         }
13562                 }
13563         }
13564         
13565 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13566         /*
13567          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13568          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13569          */
13570         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13571                 for (i = 0; i < cfg->num_varinfo; ++i) {
13572                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13573                         MonoInst *ins;
13574
13575                         if (live_range_start [vreg]) {
13576                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13577                                 ins->inst_c0 = i;
13578                                 ins->inst_c1 = vreg;
13579                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13580                         }
13581                         if (live_range_end [vreg]) {
13582                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13583                                 ins->inst_c0 = i;
13584                                 ins->inst_c1 = vreg;
13585                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13586                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13587                                 else
13588                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13589                         }
13590                 }
13591         }
13592 #endif
13593
13594         if (cfg->gsharedvt_locals_var_ins) {
13595                 /* Nullify if unused */
13596                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13597                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13598         }
13599
13600         g_free (live_range_start);
13601         g_free (live_range_end);
13602         g_free (live_range_start_bb);
13603         g_free (live_range_end_bb);
13604 }
13605
13606 /**
13607  * FIXME:
13608  * - use 'iadd' instead of 'int_add'
13609  * - handling ovf opcodes: decompose in method_to_ir.
13610  * - unify iregs/fregs
13611  *   -> partly done, the missing parts are:
13612  *   - a more complete unification would involve unifying the hregs as well, so
13613  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13614  *     would no longer map to the machine hregs, so the code generators would need to
13615  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13616  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13617  *     fp/non-fp branches speeds it up by about 15%.
13618  * - use sext/zext opcodes instead of shifts
13619  * - add OP_ICALL
13620  * - get rid of TEMPLOADs if possible and use vregs instead
13621  * - clean up usage of OP_P/OP_ opcodes
13622  * - cleanup usage of DUMMY_USE
13623  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13624  *   stack
13625  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13626  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13627  * - make sure handle_stack_args () is called before the branch is emitted
13628  * - when the new IR is done, get rid of all unused stuff
13629  * - COMPARE/BEQ as separate instructions or unify them ?
13630  *   - keeping them separate allows specialized compare instructions like
13631  *     compare_imm, compare_membase
13632  *   - most back ends unify fp compare+branch, fp compare+ceq
13633  * - integrate mono_save_args into inline_method
13634  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13635  * - handle long shift opts on 32 bit platforms somehow: they require 
13636  *   3 sregs (2 for arg1 and 1 for arg2)
13637  * - make byref a 'normal' type.
13638  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13639  *   variable if needed.
13640  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13641  *   like inline_method.
13642  * - remove inlining restrictions
13643  * - fix LNEG and enable cfold of INEG
13644  * - generalize x86 optimizations like ldelema as a peephole optimization
13645  * - add store_mem_imm for amd64
13646  * - optimize the loading of the interruption flag in the managed->native wrappers
13647  * - avoid special handling of OP_NOP in passes
13648  * - move code inserting instructions into one function/macro.
13649  * - try a coalescing phase after liveness analysis
13650  * - add float -> vreg conversion + local optimizations on !x86
13651  * - figure out how to handle decomposed branches during optimizations, ie.
13652  *   compare+branch, op_jump_table+op_br etc.
13653  * - promote RuntimeXHandles to vregs
13654  * - vtype cleanups:
13655  *   - add a NEW_VARLOADA_VREG macro
13656  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13657  *   accessing vtype fields.
13658  * - get rid of I8CONST on 64 bit platforms
13659  * - dealing with the increase in code size due to branches created during opcode
13660  *   decomposition:
13661  *   - use extended basic blocks
13662  *     - all parts of the JIT
13663  *     - handle_global_vregs () && local regalloc
13664  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13665  * - sources of increase in code size:
13666  *   - vtypes
13667  *   - long compares
13668  *   - isinst and castclass
13669  *   - lvregs not allocated to global registers even if used multiple times
13670  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13671  *   meaningful.
13672  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13673  * - add all micro optimizations from the old JIT
13674  * - put tree optimizations into the deadce pass
13675  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13676  *   specific function.
13677  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13678  *   fcompare + branchCC.
13679  * - create a helper function for allocating a stack slot, taking into account 
13680  *   MONO_CFG_HAS_SPILLUP.
13681  * - merge r68207.
13682  * - merge the ia64 switch changes.
13683  * - optimize mono_regstate2_alloc_int/float.
13684  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13685  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13686  *   parts of the tree could be separated by other instructions, killing the tree
13687  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13688  *   instructions if the result of the load is used multiple times ?
13689  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13690  * - LAST MERGE: 108395.
13691  * - when returning vtypes in registers, generate IR and append it to the end of the
13692  *   last bb instead of doing it in the epilog.
13693  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13694  */
13695
13696 /*
13697
13698 NOTES
13699 -----
13700
13701 - When to decompose opcodes:
13702   - earlier: this makes some optimizations hard to implement, since the low level IR
13703   no longer contains the neccessary information. But it is easier to do.
13704   - later: harder to implement, enables more optimizations.
13705 - Branches inside bblocks:
13706   - created when decomposing complex opcodes. 
13707     - branches to another bblock: harmless, but not tracked by the branch 
13708       optimizations, so need to branch to a label at the start of the bblock.
13709     - branches to inside the same bblock: very problematic, trips up the local
13710       reg allocator. Can be fixed by spitting the current bblock, but that is a
13711       complex operation, since some local vregs can become global vregs etc.
13712 - Local/global vregs:
13713   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13714     local register allocator.
13715   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13716     structure, created by mono_create_var (). Assigned to hregs or the stack by
13717     the global register allocator.
13718 - When to do optimizations like alu->alu_imm:
13719   - earlier -> saves work later on since the IR will be smaller/simpler
13720   - later -> can work on more instructions
13721 - Handling of valuetypes:
13722   - When a vtype is pushed on the stack, a new temporary is created, an 
13723     instruction computing its address (LDADDR) is emitted and pushed on
13724     the stack. Need to optimize cases when the vtype is used immediately as in
13725     argument passing, stloc etc.
13726 - Instead of the to_end stuff in the old JIT, simply call the function handling
13727   the values on the stack before emitting the last instruction of the bb.
13728 */
13729
13730 #endif /* DISABLE_JIT */