Merge pull request #832 from xplicit/webperf1
[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 /* Determine whenever 'ins' represents a load of the 'this' argument */
125 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
126
127 static int ldind_to_load_membase (int opcode);
128 static int stind_to_store_membase (int opcode);
129
130 int mono_op_to_op_imm (int opcode);
131 int mono_op_to_op_imm_noemul (int opcode);
132
133 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
134
135 /* helper methods signatures */
136 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
137 static MonoMethodSignature *helper_sig_domain_get = NULL;
138 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
139 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
140 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
141 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
142 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
143
144 /*
145  * Instruction metadata
146  */
147 #ifdef MINI_OP
148 #undef MINI_OP
149 #endif
150 #ifdef MINI_OP3
151 #undef MINI_OP3
152 #endif
153 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
154 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
155 #define NONE ' '
156 #define IREG 'i'
157 #define FREG 'f'
158 #define VREG 'v'
159 #define XREG 'x'
160 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
161 #define LREG IREG
162 #else
163 #define LREG 'l'
164 #endif
165 /* keep in sync with the enum in mini.h */
166 const char
167 ins_info[] = {
168 #include "mini-ops.h"
169 };
170 #undef MINI_OP
171 #undef MINI_OP3
172
173 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
174 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
175 /* 
176  * This should contain the index of the last sreg + 1. This is not the same
177  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
178  */
179 const gint8 ins_sreg_counts[] = {
180 #include "mini-ops.h"
181 };
182 #undef MINI_OP
183 #undef MINI_OP3
184
185 #define MONO_INIT_VARINFO(vi,id) do { \
186         (vi)->range.first_use.pos.bid = 0xffff; \
187         (vi)->reg = -1; \
188         (vi)->idx = (id); \
189 } while (0)
190
191 void
192 mono_inst_set_src_registers (MonoInst *ins, int *regs)
193 {
194         ins->sreg1 = regs [0];
195         ins->sreg2 = regs [1];
196         ins->sreg3 = regs [2];
197 }
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_freg (MonoCompile *cfg)
207 {
208         return alloc_freg (cfg);
209 }
210
211 guint32
212 mono_alloc_preg (MonoCompile *cfg)
213 {
214         return alloc_preg (cfg);
215 }
216
217 guint32
218 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
219 {
220         return alloc_dreg (cfg, stack_type);
221 }
222
223 /*
224  * mono_alloc_ireg_ref:
225  *
226  *   Allocate an IREG, and mark it as holding a GC ref.
227  */
228 guint32
229 mono_alloc_ireg_ref (MonoCompile *cfg)
230 {
231         return alloc_ireg_ref (cfg);
232 }
233
234 /*
235  * mono_alloc_ireg_mp:
236  *
237  *   Allocate an IREG, and mark it as holding a managed pointer.
238  */
239 guint32
240 mono_alloc_ireg_mp (MonoCompile *cfg)
241 {
242         return alloc_ireg_mp (cfg);
243 }
244
245 /*
246  * mono_alloc_ireg_copy:
247  *
248  *   Allocate an IREG with the same GC type as VREG.
249  */
250 guint32
251 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
252 {
253         if (vreg_is_ref (cfg, vreg))
254                 return alloc_ireg_ref (cfg);
255         else if (vreg_is_mp (cfg, vreg))
256                 return alloc_ireg_mp (cfg);
257         else
258                 return alloc_ireg (cfg);
259 }
260
261 guint
262 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
263 {
264         if (type->byref)
265                 return OP_MOVE;
266
267         type = mini_replace_type (type);
268 handle_enum:
269         switch (type->type) {
270         case MONO_TYPE_I1:
271         case MONO_TYPE_U1:
272         case MONO_TYPE_BOOLEAN:
273                 return OP_MOVE;
274         case MONO_TYPE_I2:
275         case MONO_TYPE_U2:
276         case MONO_TYPE_CHAR:
277                 return OP_MOVE;
278         case MONO_TYPE_I4:
279         case MONO_TYPE_U4:
280                 return OP_MOVE;
281         case MONO_TYPE_I:
282         case MONO_TYPE_U:
283         case MONO_TYPE_PTR:
284         case MONO_TYPE_FNPTR:
285                 return OP_MOVE;
286         case MONO_TYPE_CLASS:
287         case MONO_TYPE_STRING:
288         case MONO_TYPE_OBJECT:
289         case MONO_TYPE_SZARRAY:
290         case MONO_TYPE_ARRAY:    
291                 return OP_MOVE;
292         case MONO_TYPE_I8:
293         case MONO_TYPE_U8:
294 #if SIZEOF_REGISTER == 8
295                 return OP_MOVE;
296 #else
297                 return OP_LMOVE;
298 #endif
299         case MONO_TYPE_R4:
300                 return OP_FMOVE;
301         case MONO_TYPE_R8:
302                 return OP_FMOVE;
303         case MONO_TYPE_VALUETYPE:
304                 if (type->data.klass->enumtype) {
305                         type = mono_class_enum_basetype (type->data.klass);
306                         goto handle_enum;
307                 }
308                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
309                         return OP_XMOVE;
310                 return OP_VMOVE;
311         case MONO_TYPE_TYPEDBYREF:
312                 return OP_VMOVE;
313         case MONO_TYPE_GENERICINST:
314                 type = &type->data.generic_class->container_class->byval_arg;
315                 goto handle_enum;
316         case MONO_TYPE_VAR:
317         case MONO_TYPE_MVAR:
318                 g_assert (cfg->generic_sharing_context);
319                 if (mini_type_var_is_vt (cfg, type))
320                         return OP_VMOVE;
321                 else
322                         return OP_MOVE;
323         default:
324                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
325         }
326         return -1;
327 }
328
329 void
330 mono_print_bb (MonoBasicBlock *bb, const char *msg)
331 {
332         int i;
333         MonoInst *tree;
334
335         printf ("\n%s %d: [IN: ", msg, bb->block_num);
336         for (i = 0; i < bb->in_count; ++i)
337                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
338         printf (", OUT: ");
339         for (i = 0; i < bb->out_count; ++i)
340                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
341         printf (" ]\n");
342         for (tree = bb->code; tree; tree = tree->next)
343                 mono_print_ins_index (-1, tree);
344 }
345
346 void
347 mono_create_helper_signatures (void)
348 {
349         helper_sig_domain_get = mono_create_icall_signature ("ptr");
350         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
351         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
352         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
353         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
354         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
355         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
356 }
357
358 /*
359  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
360  * foo<T> (int i) { ldarg.0; box T; }
361  */
362 #define UNVERIFIED do { \
363         if (cfg->gsharedvt) { \
364                 if (cfg->verbose_level > 2)                                                                     \
365                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
366                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
367                 goto exception_exit;                                                                                    \
368         }                                                                                                                                       \
369         if (mini_get_debug_options ()->break_on_unverified) \
370                 G_BREAKPOINT (); \
371         else \
372                 goto unverified; \
373 } while (0)
374
375 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
376
377 #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)
378
379 #define GET_BBLOCK(cfg,tblock,ip) do {  \
380                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
381                 if (!(tblock)) {        \
382                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
383             NEW_BBLOCK (cfg, (tblock)); \
384                         (tblock)->cil_code = (ip);      \
385                         ADD_BBLOCK (cfg, (tblock));     \
386                 } \
387         } while (0)
388
389 #if defined(TARGET_X86) || defined(TARGET_AMD64)
390 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
391                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
392                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
393                 (dest)->sreg1 = (sr1); \
394                 (dest)->sreg2 = (sr2); \
395                 (dest)->inst_imm = (imm); \
396                 (dest)->backend.shift_amount = (shift); \
397                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
398         } while (0)
399 #endif
400
401 #if SIZEOF_REGISTER == 8
402 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
403                 /* FIXME: Need to add many more cases */ \
404                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
405                         MonoInst *widen; \
406                         int dr = alloc_preg (cfg); \
407                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
408                         (ins)->sreg2 = widen->dreg; \
409                 } \
410         } while (0)
411 #else
412 #define ADD_WIDEN_OP(ins, arg1, arg2)
413 #endif
414
415 #define ADD_BINOP(op) do {      \
416                 MONO_INST_NEW (cfg, ins, (op)); \
417                 sp -= 2;        \
418                 ins->sreg1 = sp [0]->dreg;      \
419                 ins->sreg2 = sp [1]->dreg;      \
420                 type_from_op (ins, sp [0], sp [1]);     \
421                 CHECK_TYPE (ins);       \
422                 /* Have to insert a widening op */               \
423         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
424         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
425         MONO_ADD_INS ((cfg)->cbb, (ins)); \
426         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
427         } while (0)
428
429 #define ADD_UNOP(op) do {       \
430                 MONO_INST_NEW (cfg, ins, (op)); \
431                 sp--;   \
432                 ins->sreg1 = sp [0]->dreg;      \
433                 type_from_op (ins, sp [0], NULL);       \
434                 CHECK_TYPE (ins);       \
435         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
436         MONO_ADD_INS ((cfg)->cbb, (ins)); \
437                 *sp++ = mono_decompose_opcode (cfg, ins); \
438         } while (0)
439
440 #define ADD_BINCOND(next_block) do {    \
441                 MonoInst *cmp;  \
442                 sp -= 2; \
443                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
444                 cmp->sreg1 = sp [0]->dreg;      \
445                 cmp->sreg2 = sp [1]->dreg;      \
446                 type_from_op (cmp, sp [0], sp [1]);     \
447                 CHECK_TYPE (cmp);       \
448                 type_from_op (ins, sp [0], sp [1]);     \
449                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
450                 GET_BBLOCK (cfg, tblock, target);               \
451                 link_bblock (cfg, bblock, tblock);      \
452                 ins->inst_true_bb = tblock;     \
453                 if ((next_block)) {     \
454                         link_bblock (cfg, bblock, (next_block));        \
455                         ins->inst_false_bb = (next_block);      \
456                         start_new_bblock = 1;   \
457                 } else {        \
458                         GET_BBLOCK (cfg, tblock, ip);           \
459                         link_bblock (cfg, bblock, tblock);      \
460                         ins->inst_false_bb = tblock;    \
461                         start_new_bblock = 2;   \
462                 }       \
463                 if (sp != stack_start) {                                                                        \
464                     handle_stack_args (cfg, stack_start, sp - stack_start); \
465                         CHECK_UNVERIFIABLE (cfg); \
466                 } \
467         MONO_ADD_INS (bblock, cmp); \
468                 MONO_ADD_INS (bblock, ins);     \
469         } while (0)
470
471 /* *
472  * link_bblock: Links two basic blocks
473  *
474  * links two basic blocks in the control flow graph, the 'from'
475  * argument is the starting block and the 'to' argument is the block
476  * the control flow ends to after 'from'.
477  */
478 static void
479 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
480 {
481         MonoBasicBlock **newa;
482         int i, found;
483
484 #if 0
485         if (from->cil_code) {
486                 if (to->cil_code)
487                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
488                 else
489                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
490         } else {
491                 if (to->cil_code)
492                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
493                 else
494                         printf ("edge from entry to exit\n");
495         }
496 #endif
497
498         found = FALSE;
499         for (i = 0; i < from->out_count; ++i) {
500                 if (to == from->out_bb [i]) {
501                         found = TRUE;
502                         break;
503                 }
504         }
505         if (!found) {
506                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
507                 for (i = 0; i < from->out_count; ++i) {
508                         newa [i] = from->out_bb [i];
509                 }
510                 newa [i] = to;
511                 from->out_count++;
512                 from->out_bb = newa;
513         }
514
515         found = FALSE;
516         for (i = 0; i < to->in_count; ++i) {
517                 if (from == to->in_bb [i]) {
518                         found = TRUE;
519                         break;
520                 }
521         }
522         if (!found) {
523                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
524                 for (i = 0; i < to->in_count; ++i) {
525                         newa [i] = to->in_bb [i];
526                 }
527                 newa [i] = from;
528                 to->in_count++;
529                 to->in_bb = newa;
530         }
531 }
532
533 void
534 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
535 {
536         link_bblock (cfg, from, to);
537 }
538
539 /**
540  * mono_find_block_region:
541  *
542  *   We mark each basic block with a region ID. We use that to avoid BB
543  *   optimizations when blocks are in different regions.
544  *
545  * Returns:
546  *   A region token that encodes where this region is, and information
547  *   about the clause owner for this block.
548  *
549  *   The region encodes the try/catch/filter clause that owns this block
550  *   as well as the type.  -1 is a special value that represents a block
551  *   that is in none of try/catch/filter.
552  */
553 static int
554 mono_find_block_region (MonoCompile *cfg, int offset)
555 {
556         MonoMethodHeader *header = cfg->header;
557         MonoExceptionClause *clause;
558         int i;
559
560         for (i = 0; i < header->num_clauses; ++i) {
561                 clause = &header->clauses [i];
562                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
563                     (offset < (clause->handler_offset)))
564                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
565                            
566                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
567                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
568                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
569                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
570                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
571                         else
572                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
573                 }
574
575                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
576                         return ((i + 1) << 8) | clause->flags;
577         }
578
579         return -1;
580 }
581
582 static GList*
583 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
584 {
585         MonoMethodHeader *header = cfg->header;
586         MonoExceptionClause *clause;
587         int i;
588         GList *res = NULL;
589
590         for (i = 0; i < header->num_clauses; ++i) {
591                 clause = &header->clauses [i];
592                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
593                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
594                         if (clause->flags == type)
595                                 res = g_list_append (res, clause);
596                 }
597         }
598         return res;
599 }
600
601 static void
602 mono_create_spvar_for_region (MonoCompile *cfg, int region)
603 {
604         MonoInst *var;
605
606         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
607         if (var)
608                 return;
609
610         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
611         /* prevent it from being register allocated */
612         var->flags |= MONO_INST_VOLATILE;
613
614         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
615 }
616
617 MonoInst *
618 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
619 {
620         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
621 }
622
623 static MonoInst*
624 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
625 {
626         MonoInst *var;
627
628         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
629         if (var)
630                 return var;
631
632         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
633         /* prevent it from being register allocated */
634         var->flags |= MONO_INST_VOLATILE;
635
636         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
637
638         return var;
639 }
640
641 /*
642  * Returns the type used in the eval stack when @type is loaded.
643  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
644  */
645 void
646 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
647 {
648         MonoClass *klass;
649
650         type = mini_replace_type (type);
651         inst->klass = klass = mono_class_from_mono_type (type);
652         if (type->byref) {
653                 inst->type = STACK_MP;
654                 return;
655         }
656
657 handle_enum:
658         switch (type->type) {
659         case MONO_TYPE_VOID:
660                 inst->type = STACK_INV;
661                 return;
662         case MONO_TYPE_I1:
663         case MONO_TYPE_U1:
664         case MONO_TYPE_BOOLEAN:
665         case MONO_TYPE_I2:
666         case MONO_TYPE_U2:
667         case MONO_TYPE_CHAR:
668         case MONO_TYPE_I4:
669         case MONO_TYPE_U4:
670                 inst->type = STACK_I4;
671                 return;
672         case MONO_TYPE_I:
673         case MONO_TYPE_U:
674         case MONO_TYPE_PTR:
675         case MONO_TYPE_FNPTR:
676                 inst->type = STACK_PTR;
677                 return;
678         case MONO_TYPE_CLASS:
679         case MONO_TYPE_STRING:
680         case MONO_TYPE_OBJECT:
681         case MONO_TYPE_SZARRAY:
682         case MONO_TYPE_ARRAY:    
683                 inst->type = STACK_OBJ;
684                 return;
685         case MONO_TYPE_I8:
686         case MONO_TYPE_U8:
687                 inst->type = STACK_I8;
688                 return;
689         case MONO_TYPE_R4:
690         case MONO_TYPE_R8:
691                 inst->type = STACK_R8;
692                 return;
693         case MONO_TYPE_VALUETYPE:
694                 if (type->data.klass->enumtype) {
695                         type = mono_class_enum_basetype (type->data.klass);
696                         goto handle_enum;
697                 } else {
698                         inst->klass = klass;
699                         inst->type = STACK_VTYPE;
700                         return;
701                 }
702         case MONO_TYPE_TYPEDBYREF:
703                 inst->klass = mono_defaults.typed_reference_class;
704                 inst->type = STACK_VTYPE;
705                 return;
706         case MONO_TYPE_GENERICINST:
707                 type = &type->data.generic_class->container_class->byval_arg;
708                 goto handle_enum;
709         case MONO_TYPE_VAR:
710         case MONO_TYPE_MVAR:
711                 g_assert (cfg->generic_sharing_context);
712                 if (mini_is_gsharedvt_type (cfg, type)) {
713                         g_assert (cfg->gsharedvt);
714                         inst->type = STACK_VTYPE;
715                 } else {
716                         inst->type = STACK_OBJ;
717                 }
718                 return;
719         default:
720                 g_error ("unknown type 0x%02x in eval stack type", type->type);
721         }
722 }
723
724 /*
725  * The following tables are used to quickly validate the IL code in type_from_op ().
726  */
727 static const char
728 bin_num_table [STACK_MAX] [STACK_MAX] = {
729         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
730         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
731         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
732         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
733         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
734         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
735         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
736         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
737 };
738
739 static const char 
740 neg_table [] = {
741         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
742 };
743
744 /* reduce the size of this table */
745 static const char
746 bin_int_table [STACK_MAX] [STACK_MAX] = {
747         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
748         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
749         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
750         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
751         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
752         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
753         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
754         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
755 };
756
757 static const char
758 bin_comp_table [STACK_MAX] [STACK_MAX] = {
759 /*      Inv i  L  p  F  &  O  vt */
760         {0},
761         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
762         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
763         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
764         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
765         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
766         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
767         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
768 };
769
770 /* reduce the size of this table */
771 static const char
772 shift_table [STACK_MAX] [STACK_MAX] = {
773         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
774         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
775         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
776         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
777         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
778         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
779         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
780         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
781 };
782
783 /*
784  * Tables to map from the non-specific opcode to the matching
785  * type-specific opcode.
786  */
787 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
788 static const guint16
789 binops_op_map [STACK_MAX] = {
790         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
791 };
792
793 /* handles from CEE_NEG to CEE_CONV_U8 */
794 static const guint16
795 unops_op_map [STACK_MAX] = {
796         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
797 };
798
799 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
800 static const guint16
801 ovfops_op_map [STACK_MAX] = {
802         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
803 };
804
805 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
806 static const guint16
807 ovf2ops_op_map [STACK_MAX] = {
808         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
809 };
810
811 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
812 static const guint16
813 ovf3ops_op_map [STACK_MAX] = {
814         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
815 };
816
817 /* handles from CEE_BEQ to CEE_BLT_UN */
818 static const guint16
819 beqops_op_map [STACK_MAX] = {
820         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
821 };
822
823 /* handles from CEE_CEQ to CEE_CLT_UN */
824 static const guint16
825 ceqops_op_map [STACK_MAX] = {
826         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
827 };
828
829 /*
830  * Sets ins->type (the type on the eval stack) according to the
831  * type of the opcode and the arguments to it.
832  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
833  *
834  * FIXME: this function sets ins->type unconditionally in some cases, but
835  * it should set it to invalid for some types (a conv.x on an object)
836  */
837 static void
838 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
839
840         switch (ins->opcode) {
841         /* binops */
842         case CEE_ADD:
843         case CEE_SUB:
844         case CEE_MUL:
845         case CEE_DIV:
846         case CEE_REM:
847                 /* FIXME: check unverifiable args for STACK_MP */
848                 ins->type = bin_num_table [src1->type] [src2->type];
849                 ins->opcode += binops_op_map [ins->type];
850                 break;
851         case CEE_DIV_UN:
852         case CEE_REM_UN:
853         case CEE_AND:
854         case CEE_OR:
855         case CEE_XOR:
856                 ins->type = bin_int_table [src1->type] [src2->type];
857                 ins->opcode += binops_op_map [ins->type];
858                 break;
859         case CEE_SHL:
860         case CEE_SHR:
861         case CEE_SHR_UN:
862                 ins->type = shift_table [src1->type] [src2->type];
863                 ins->opcode += binops_op_map [ins->type];
864                 break;
865         case OP_COMPARE:
866         case OP_LCOMPARE:
867         case OP_ICOMPARE:
868                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
869                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
870                         ins->opcode = OP_LCOMPARE;
871                 else if (src1->type == STACK_R8)
872                         ins->opcode = OP_FCOMPARE;
873                 else
874                         ins->opcode = OP_ICOMPARE;
875                 break;
876         case OP_ICOMPARE_IMM:
877                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
878                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
879                         ins->opcode = OP_LCOMPARE_IMM;          
880                 break;
881         case CEE_BEQ:
882         case CEE_BGE:
883         case CEE_BGT:
884         case CEE_BLE:
885         case CEE_BLT:
886         case CEE_BNE_UN:
887         case CEE_BGE_UN:
888         case CEE_BGT_UN:
889         case CEE_BLE_UN:
890         case CEE_BLT_UN:
891                 ins->opcode += beqops_op_map [src1->type];
892                 break;
893         case OP_CEQ:
894                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
895                 ins->opcode += ceqops_op_map [src1->type];
896                 break;
897         case OP_CGT:
898         case OP_CGT_UN:
899         case OP_CLT:
900         case OP_CLT_UN:
901                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
902                 ins->opcode += ceqops_op_map [src1->type];
903                 break;
904         /* unops */
905         case CEE_NEG:
906                 ins->type = neg_table [src1->type];
907                 ins->opcode += unops_op_map [ins->type];
908                 break;
909         case CEE_NOT:
910                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
911                         ins->type = src1->type;
912                 else
913                         ins->type = STACK_INV;
914                 ins->opcode += unops_op_map [ins->type];
915                 break;
916         case CEE_CONV_I1:
917         case CEE_CONV_I2:
918         case CEE_CONV_I4:
919         case CEE_CONV_U4:
920                 ins->type = STACK_I4;
921                 ins->opcode += unops_op_map [src1->type];
922                 break;
923         case CEE_CONV_R_UN:
924                 ins->type = STACK_R8;
925                 switch (src1->type) {
926                 case STACK_I4:
927                 case STACK_PTR:
928                         ins->opcode = OP_ICONV_TO_R_UN;
929                         break;
930                 case STACK_I8:
931                         ins->opcode = OP_LCONV_TO_R_UN; 
932                         break;
933                 }
934                 break;
935         case CEE_CONV_OVF_I1:
936         case CEE_CONV_OVF_U1:
937         case CEE_CONV_OVF_I2:
938         case CEE_CONV_OVF_U2:
939         case CEE_CONV_OVF_I4:
940         case CEE_CONV_OVF_U4:
941                 ins->type = STACK_I4;
942                 ins->opcode += ovf3ops_op_map [src1->type];
943                 break;
944         case CEE_CONV_OVF_I_UN:
945         case CEE_CONV_OVF_U_UN:
946                 ins->type = STACK_PTR;
947                 ins->opcode += ovf2ops_op_map [src1->type];
948                 break;
949         case CEE_CONV_OVF_I1_UN:
950         case CEE_CONV_OVF_I2_UN:
951         case CEE_CONV_OVF_I4_UN:
952         case CEE_CONV_OVF_U1_UN:
953         case CEE_CONV_OVF_U2_UN:
954         case CEE_CONV_OVF_U4_UN:
955                 ins->type = STACK_I4;
956                 ins->opcode += ovf2ops_op_map [src1->type];
957                 break;
958         case CEE_CONV_U:
959                 ins->type = STACK_PTR;
960                 switch (src1->type) {
961                 case STACK_I4:
962                         ins->opcode = OP_ICONV_TO_U;
963                         break;
964                 case STACK_PTR:
965                 case STACK_MP:
966 #if SIZEOF_VOID_P == 8
967                         ins->opcode = OP_LCONV_TO_U;
968 #else
969                         ins->opcode = OP_MOVE;
970 #endif
971                         break;
972                 case STACK_I8:
973                         ins->opcode = OP_LCONV_TO_U;
974                         break;
975                 case STACK_R8:
976                         ins->opcode = OP_FCONV_TO_U;
977                         break;
978                 }
979                 break;
980         case CEE_CONV_I8:
981         case CEE_CONV_U8:
982                 ins->type = STACK_I8;
983                 ins->opcode += unops_op_map [src1->type];
984                 break;
985         case CEE_CONV_OVF_I8:
986         case CEE_CONV_OVF_U8:
987                 ins->type = STACK_I8;
988                 ins->opcode += ovf3ops_op_map [src1->type];
989                 break;
990         case CEE_CONV_OVF_U8_UN:
991         case CEE_CONV_OVF_I8_UN:
992                 ins->type = STACK_I8;
993                 ins->opcode += ovf2ops_op_map [src1->type];
994                 break;
995         case CEE_CONV_R4:
996         case CEE_CONV_R8:
997                 ins->type = STACK_R8;
998                 ins->opcode += unops_op_map [src1->type];
999                 break;
1000         case OP_CKFINITE:
1001                 ins->type = STACK_R8;           
1002                 break;
1003         case CEE_CONV_U2:
1004         case CEE_CONV_U1:
1005                 ins->type = STACK_I4;
1006                 ins->opcode += ovfops_op_map [src1->type];
1007                 break;
1008         case CEE_CONV_I:
1009         case CEE_CONV_OVF_I:
1010         case CEE_CONV_OVF_U:
1011                 ins->type = STACK_PTR;
1012                 ins->opcode += ovfops_op_map [src1->type];
1013                 break;
1014         case CEE_ADD_OVF:
1015         case CEE_ADD_OVF_UN:
1016         case CEE_MUL_OVF:
1017         case CEE_MUL_OVF_UN:
1018         case CEE_SUB_OVF:
1019         case CEE_SUB_OVF_UN:
1020                 ins->type = bin_num_table [src1->type] [src2->type];
1021                 ins->opcode += ovfops_op_map [src1->type];
1022                 if (ins->type == STACK_R8)
1023                         ins->type = STACK_INV;
1024                 break;
1025         case OP_LOAD_MEMBASE:
1026                 ins->type = STACK_PTR;
1027                 break;
1028         case OP_LOADI1_MEMBASE:
1029         case OP_LOADU1_MEMBASE:
1030         case OP_LOADI2_MEMBASE:
1031         case OP_LOADU2_MEMBASE:
1032         case OP_LOADI4_MEMBASE:
1033         case OP_LOADU4_MEMBASE:
1034                 ins->type = STACK_PTR;
1035                 break;
1036         case OP_LOADI8_MEMBASE:
1037                 ins->type = STACK_I8;
1038                 break;
1039         case OP_LOADR4_MEMBASE:
1040         case OP_LOADR8_MEMBASE:
1041                 ins->type = STACK_R8;
1042                 break;
1043         default:
1044                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1045                 break;
1046         }
1047
1048         if (ins->type == STACK_MP)
1049                 ins->klass = mono_defaults.object_class;
1050 }
1051
1052 static const char 
1053 ldind_type [] = {
1054         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1055 };
1056
1057 #if 0
1058
1059 static const char
1060 param_table [STACK_MAX] [STACK_MAX] = {
1061         {0},
1062 };
1063
1064 static int
1065 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1066         int i;
1067
1068         if (sig->hasthis) {
1069                 switch (args->type) {
1070                 case STACK_I4:
1071                 case STACK_I8:
1072                 case STACK_R8:
1073                 case STACK_VTYPE:
1074                 case STACK_INV:
1075                         return 0;
1076                 }
1077                 args++;
1078         }
1079         for (i = 0; i < sig->param_count; ++i) {
1080                 switch (args [i].type) {
1081                 case STACK_INV:
1082                         return 0;
1083                 case STACK_MP:
1084                         if (!sig->params [i]->byref)
1085                                 return 0;
1086                         continue;
1087                 case STACK_OBJ:
1088                         if (sig->params [i]->byref)
1089                                 return 0;
1090                         switch (sig->params [i]->type) {
1091                         case MONO_TYPE_CLASS:
1092                         case MONO_TYPE_STRING:
1093                         case MONO_TYPE_OBJECT:
1094                         case MONO_TYPE_SZARRAY:
1095                         case MONO_TYPE_ARRAY:
1096                                 break;
1097                         default:
1098                                 return 0;
1099                         }
1100                         continue;
1101                 case STACK_R8:
1102                         if (sig->params [i]->byref)
1103                                 return 0;
1104                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1105                                 return 0;
1106                         continue;
1107                 case STACK_PTR:
1108                 case STACK_I4:
1109                 case STACK_I8:
1110                 case STACK_VTYPE:
1111                         break;
1112                 }
1113                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1114                         return 0;*/
1115         }
1116         return 1;
1117 }
1118 #endif
1119
1120 /*
1121  * When we need a pointer to the current domain many times in a method, we
1122  * call mono_domain_get() once and we store the result in a local variable.
1123  * This function returns the variable that represents the MonoDomain*.
1124  */
1125 inline static MonoInst *
1126 mono_get_domainvar (MonoCompile *cfg)
1127 {
1128         if (!cfg->domainvar)
1129                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1130         return cfg->domainvar;
1131 }
1132
1133 /*
1134  * The got_var contains the address of the Global Offset Table when AOT 
1135  * compiling.
1136  */
1137 MonoInst *
1138 mono_get_got_var (MonoCompile *cfg)
1139 {
1140 #ifdef MONO_ARCH_NEED_GOT_VAR
1141         if (!cfg->compile_aot)
1142                 return NULL;
1143         if (!cfg->got_var) {
1144                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1145         }
1146         return cfg->got_var;
1147 #else
1148         return NULL;
1149 #endif
1150 }
1151
1152 static MonoInst *
1153 mono_get_vtable_var (MonoCompile *cfg)
1154 {
1155         g_assert (cfg->generic_sharing_context);
1156
1157         if (!cfg->rgctx_var) {
1158                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1159                 /* force the var to be stack allocated */
1160                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1161         }
1162
1163         return cfg->rgctx_var;
1164 }
1165
1166 static MonoType*
1167 type_from_stack_type (MonoInst *ins) {
1168         switch (ins->type) {
1169         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1170         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1171         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1172         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1173         case STACK_MP:
1174                 return &ins->klass->this_arg;
1175         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1176         case STACK_VTYPE: return &ins->klass->byval_arg;
1177         default:
1178                 g_error ("stack type %d to monotype not handled\n", ins->type);
1179         }
1180         return NULL;
1181 }
1182
1183 static G_GNUC_UNUSED int
1184 type_to_stack_type (MonoType *t)
1185 {
1186         t = mono_type_get_underlying_type (t);
1187         switch (t->type) {
1188         case MONO_TYPE_I1:
1189         case MONO_TYPE_U1:
1190         case MONO_TYPE_BOOLEAN:
1191         case MONO_TYPE_I2:
1192         case MONO_TYPE_U2:
1193         case MONO_TYPE_CHAR:
1194         case MONO_TYPE_I4:
1195         case MONO_TYPE_U4:
1196                 return STACK_I4;
1197         case MONO_TYPE_I:
1198         case MONO_TYPE_U:
1199         case MONO_TYPE_PTR:
1200         case MONO_TYPE_FNPTR:
1201                 return STACK_PTR;
1202         case MONO_TYPE_CLASS:
1203         case MONO_TYPE_STRING:
1204         case MONO_TYPE_OBJECT:
1205         case MONO_TYPE_SZARRAY:
1206         case MONO_TYPE_ARRAY:    
1207                 return STACK_OBJ;
1208         case MONO_TYPE_I8:
1209         case MONO_TYPE_U8:
1210                 return STACK_I8;
1211         case MONO_TYPE_R4:
1212         case MONO_TYPE_R8:
1213                 return STACK_R8;
1214         case MONO_TYPE_VALUETYPE:
1215         case MONO_TYPE_TYPEDBYREF:
1216                 return STACK_VTYPE;
1217         case MONO_TYPE_GENERICINST:
1218                 if (mono_type_generic_inst_is_valuetype (t))
1219                         return STACK_VTYPE;
1220                 else
1221                         return STACK_OBJ;
1222                 break;
1223         default:
1224                 g_assert_not_reached ();
1225         }
1226
1227         return -1;
1228 }
1229
1230 static MonoClass*
1231 array_access_to_klass (int opcode)
1232 {
1233         switch (opcode) {
1234         case CEE_LDELEM_U1:
1235                 return mono_defaults.byte_class;
1236         case CEE_LDELEM_U2:
1237                 return mono_defaults.uint16_class;
1238         case CEE_LDELEM_I:
1239         case CEE_STELEM_I:
1240                 return mono_defaults.int_class;
1241         case CEE_LDELEM_I1:
1242         case CEE_STELEM_I1:
1243                 return mono_defaults.sbyte_class;
1244         case CEE_LDELEM_I2:
1245         case CEE_STELEM_I2:
1246                 return mono_defaults.int16_class;
1247         case CEE_LDELEM_I4:
1248         case CEE_STELEM_I4:
1249                 return mono_defaults.int32_class;
1250         case CEE_LDELEM_U4:
1251                 return mono_defaults.uint32_class;
1252         case CEE_LDELEM_I8:
1253         case CEE_STELEM_I8:
1254                 return mono_defaults.int64_class;
1255         case CEE_LDELEM_R4:
1256         case CEE_STELEM_R4:
1257                 return mono_defaults.single_class;
1258         case CEE_LDELEM_R8:
1259         case CEE_STELEM_R8:
1260                 return mono_defaults.double_class;
1261         case CEE_LDELEM_REF:
1262         case CEE_STELEM_REF:
1263                 return mono_defaults.object_class;
1264         default:
1265                 g_assert_not_reached ();
1266         }
1267         return NULL;
1268 }
1269
1270 /*
1271  * We try to share variables when possible
1272  */
1273 static MonoInst *
1274 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1275 {
1276         MonoInst *res;
1277         int pos, vnum;
1278
1279         /* inlining can result in deeper stacks */ 
1280         if (slot >= cfg->header->max_stack)
1281                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1282
1283         pos = ins->type - 1 + slot * STACK_MAX;
1284
1285         switch (ins->type) {
1286         case STACK_I4:
1287         case STACK_I8:
1288         case STACK_R8:
1289         case STACK_PTR:
1290         case STACK_MP:
1291         case STACK_OBJ:
1292                 if ((vnum = cfg->intvars [pos]))
1293                         return cfg->varinfo [vnum];
1294                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1295                 cfg->intvars [pos] = res->inst_c0;
1296                 break;
1297         default:
1298                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1299         }
1300         return res;
1301 }
1302
1303 static void
1304 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1305 {
1306         /* 
1307          * Don't use this if a generic_context is set, since that means AOT can't
1308          * look up the method using just the image+token.
1309          * table == 0 means this is a reference made from a wrapper.
1310          */
1311         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1312                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1313                 jump_info_token->image = image;
1314                 jump_info_token->token = token;
1315                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1316         }
1317 }
1318
1319 /*
1320  * This function is called to handle items that are left on the evaluation stack
1321  * at basic block boundaries. What happens is that we save the values to local variables
1322  * and we reload them later when first entering the target basic block (with the
1323  * handle_loaded_temps () function).
1324  * A single joint point will use the same variables (stored in the array bb->out_stack or
1325  * bb->in_stack, if the basic block is before or after the joint point).
1326  *
1327  * This function needs to be called _before_ emitting the last instruction of
1328  * the bb (i.e. before emitting a branch).
1329  * If the stack merge fails at a join point, cfg->unverifiable is set.
1330  */
1331 static void
1332 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1333 {
1334         int i, bindex;
1335         MonoBasicBlock *bb = cfg->cbb;
1336         MonoBasicBlock *outb;
1337         MonoInst *inst, **locals;
1338         gboolean found;
1339
1340         if (!count)
1341                 return;
1342         if (cfg->verbose_level > 3)
1343                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1344         if (!bb->out_scount) {
1345                 bb->out_scount = count;
1346                 //printf ("bblock %d has out:", bb->block_num);
1347                 found = FALSE;
1348                 for (i = 0; i < bb->out_count; ++i) {
1349                         outb = bb->out_bb [i];
1350                         /* exception handlers are linked, but they should not be considered for stack args */
1351                         if (outb->flags & BB_EXCEPTION_HANDLER)
1352                                 continue;
1353                         //printf (" %d", outb->block_num);
1354                         if (outb->in_stack) {
1355                                 found = TRUE;
1356                                 bb->out_stack = outb->in_stack;
1357                                 break;
1358                         }
1359                 }
1360                 //printf ("\n");
1361                 if (!found) {
1362                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1363                         for (i = 0; i < count; ++i) {
1364                                 /* 
1365                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1366                                  * stack slot and if they are of the same type.
1367                                  * This won't cause conflicts since if 'local' is used to 
1368                                  * store one of the values in the in_stack of a bblock, then
1369                                  * the same variable will be used for the same outgoing stack 
1370                                  * slot as well. 
1371                                  * This doesn't work when inlining methods, since the bblocks
1372                                  * in the inlined methods do not inherit their in_stack from
1373                                  * the bblock they are inlined to. See bug #58863 for an
1374                                  * example.
1375                                  */
1376                                 if (cfg->inlined_method)
1377                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1378                                 else
1379                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1380                         }
1381                 }
1382         }
1383
1384         for (i = 0; i < bb->out_count; ++i) {
1385                 outb = bb->out_bb [i];
1386                 /* exception handlers are linked, but they should not be considered for stack args */
1387                 if (outb->flags & BB_EXCEPTION_HANDLER)
1388                         continue;
1389                 if (outb->in_scount) {
1390                         if (outb->in_scount != bb->out_scount) {
1391                                 cfg->unverifiable = TRUE;
1392                                 return;
1393                         }
1394                         continue; /* check they are the same locals */
1395                 }
1396                 outb->in_scount = count;
1397                 outb->in_stack = bb->out_stack;
1398         }
1399
1400         locals = bb->out_stack;
1401         cfg->cbb = bb;
1402         for (i = 0; i < count; ++i) {
1403                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1404                 inst->cil_code = sp [i]->cil_code;
1405                 sp [i] = locals [i];
1406                 if (cfg->verbose_level > 3)
1407                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1408         }
1409
1410         /*
1411          * It is possible that the out bblocks already have in_stack assigned, and
1412          * the in_stacks differ. In this case, we will store to all the different 
1413          * in_stacks.
1414          */
1415
1416         found = TRUE;
1417         bindex = 0;
1418         while (found) {
1419                 /* Find a bblock which has a different in_stack */
1420                 found = FALSE;
1421                 while (bindex < bb->out_count) {
1422                         outb = bb->out_bb [bindex];
1423                         /* exception handlers are linked, but they should not be considered for stack args */
1424                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1425                                 bindex++;
1426                                 continue;
1427                         }
1428                         if (outb->in_stack != locals) {
1429                                 for (i = 0; i < count; ++i) {
1430                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1431                                         inst->cil_code = sp [i]->cil_code;
1432                                         sp [i] = locals [i];
1433                                         if (cfg->verbose_level > 3)
1434                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1435                                 }
1436                                 locals = outb->in_stack;
1437                                 found = TRUE;
1438                                 break;
1439                         }
1440                         bindex ++;
1441                 }
1442         }
1443 }
1444
1445 /* Emit code which loads interface_offsets [klass->interface_id]
1446  * The array is stored in memory before vtable.
1447 */
1448 static void
1449 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1450 {
1451         if (cfg->compile_aot) {
1452                 int ioffset_reg = alloc_preg (cfg);
1453                 int iid_reg = alloc_preg (cfg);
1454
1455                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1456                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1457                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1458         }
1459         else {
1460                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1461         }
1462 }
1463
1464 static void
1465 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1466 {
1467         int ibitmap_reg = alloc_preg (cfg);
1468 #ifdef COMPRESSED_INTERFACE_BITMAP
1469         MonoInst *args [2];
1470         MonoInst *res, *ins;
1471         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1472         MONO_ADD_INS (cfg->cbb, ins);
1473         args [0] = ins;
1474         if (cfg->compile_aot)
1475                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1476         else
1477                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1478         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1479         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1480 #else
1481         int ibitmap_byte_reg = alloc_preg (cfg);
1482
1483         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1484
1485         if (cfg->compile_aot) {
1486                 int iid_reg = alloc_preg (cfg);
1487                 int shifted_iid_reg = alloc_preg (cfg);
1488                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1489                 int masked_iid_reg = alloc_preg (cfg);
1490                 int iid_one_bit_reg = alloc_preg (cfg);
1491                 int iid_bit_reg = alloc_preg (cfg);
1492                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1493                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1494                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1495                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1496                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1497                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1498                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1499                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1500         } else {
1501                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1502                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1503         }
1504 #endif
1505 }
1506
1507 /* 
1508  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1509  * stored in "klass_reg" implements the interface "klass".
1510  */
1511 static void
1512 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1513 {
1514         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1515 }
1516
1517 /* 
1518  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1519  * stored in "vtable_reg" implements the interface "klass".
1520  */
1521 static void
1522 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1523 {
1524         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1525 }
1526
1527 /* 
1528  * Emit code which checks whenever the interface id of @klass is smaller than
1529  * than the value given by max_iid_reg.
1530 */
1531 static void
1532 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1533                                                  MonoBasicBlock *false_target)
1534 {
1535         if (cfg->compile_aot) {
1536                 int iid_reg = alloc_preg (cfg);
1537                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1538                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1539         }
1540         else
1541                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1542         if (false_target)
1543                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1544         else
1545                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1546 }
1547
1548 /* Same as above, but obtains max_iid from a vtable */
1549 static void
1550 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1551                                                                  MonoBasicBlock *false_target)
1552 {
1553         int max_iid_reg = alloc_preg (cfg);
1554                 
1555         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1556         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1557 }
1558
1559 /* Same as above, but obtains max_iid from a klass */
1560 static void
1561 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1562                                                                  MonoBasicBlock *false_target)
1563 {
1564         int max_iid_reg = alloc_preg (cfg);
1565
1566         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1567         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1568 }
1569
1570 static void
1571 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1572 {
1573         int idepth_reg = alloc_preg (cfg);
1574         int stypes_reg = alloc_preg (cfg);
1575         int stype = alloc_preg (cfg);
1576
1577         mono_class_setup_supertypes (klass);
1578
1579         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1580                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1581                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1582                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1583         }
1584         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1585         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1586         if (klass_ins) {
1587                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1588         } else if (cfg->compile_aot) {
1589                 int const_reg = alloc_preg (cfg);
1590                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1591                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1592         } else {
1593                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1594         }
1595         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1596 }
1597
1598 static void
1599 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1600 {
1601         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1602 }
1603
1604 static void
1605 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1606 {
1607         int intf_reg = alloc_preg (cfg);
1608
1609         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1610         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1611         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1612         if (true_target)
1613                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1614         else
1615                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1616 }
1617
1618 /*
1619  * Variant of the above that takes a register to the class, not the vtable.
1620  */
1621 static void
1622 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1623 {
1624         int intf_bit_reg = alloc_preg (cfg);
1625
1626         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1627         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1628         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1629         if (true_target)
1630                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1631         else
1632                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1633 }
1634
1635 static inline void
1636 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1637 {
1638         if (klass_inst) {
1639                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1640         } else if (cfg->compile_aot) {
1641                 int const_reg = alloc_preg (cfg);
1642                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1643                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1644         } else {
1645                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1646         }
1647         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1648 }
1649
1650 static inline void
1651 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1652 {
1653         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1654 }
1655
1656 static inline void
1657 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1658 {
1659         if (cfg->compile_aot) {
1660                 int const_reg = alloc_preg (cfg);
1661                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1662                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1663         } else {
1664                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1665         }
1666         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1667 }
1668
1669 static void
1670 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1671         
1672 static void
1673 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1674 {
1675         if (klass->rank) {
1676                 int rank_reg = alloc_preg (cfg);
1677                 int eclass_reg = alloc_preg (cfg);
1678
1679                 g_assert (!klass_inst);
1680                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1681                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1682                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1683                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1684                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1685                 if (klass->cast_class == mono_defaults.object_class) {
1686                         int parent_reg = alloc_preg (cfg);
1687                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1688                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1689                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1690                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1691                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1692                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1693                 } else if (klass->cast_class == mono_defaults.enum_class) {
1694                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1695                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1696                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1697                 } else {
1698                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1699                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1700                 }
1701
1702                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1703                         /* Check that the object is a vector too */
1704                         int bounds_reg = alloc_preg (cfg);
1705                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1706                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1707                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1708                 }
1709         } else {
1710                 int idepth_reg = alloc_preg (cfg);
1711                 int stypes_reg = alloc_preg (cfg);
1712                 int stype = alloc_preg (cfg);
1713
1714                 mono_class_setup_supertypes (klass);
1715
1716                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1717                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1718                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1719                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1720                 }
1721                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1722                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1723                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1724         }
1725 }
1726
1727 static void
1728 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1729 {
1730         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1731 }
1732
1733 static void 
1734 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1735 {
1736         int val_reg;
1737
1738         g_assert (val == 0);
1739
1740         if (align == 0)
1741                 align = 4;
1742
1743         if ((size <= 4) && (size <= align)) {
1744                 switch (size) {
1745                 case 1:
1746                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1747                         return;
1748                 case 2:
1749                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1750                         return;
1751                 case 4:
1752                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1753                         return;
1754 #if SIZEOF_REGISTER == 8
1755                 case 8:
1756                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1757                         return;
1758 #endif
1759                 }
1760         }
1761
1762         val_reg = alloc_preg (cfg);
1763
1764         if (SIZEOF_REGISTER == 8)
1765                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1766         else
1767                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1768
1769         if (align < 4) {
1770                 /* This could be optimized further if neccesary */
1771                 while (size >= 1) {
1772                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1773                         offset += 1;
1774                         size -= 1;
1775                 }
1776                 return;
1777         }       
1778
1779 #if !NO_UNALIGNED_ACCESS
1780         if (SIZEOF_REGISTER == 8) {
1781                 if (offset % 8) {
1782                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1783                         offset += 4;
1784                         size -= 4;
1785                 }
1786                 while (size >= 8) {
1787                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1788                         offset += 8;
1789                         size -= 8;
1790                 }
1791         }       
1792 #endif
1793
1794         while (size >= 4) {
1795                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1796                 offset += 4;
1797                 size -= 4;
1798         }
1799         while (size >= 2) {
1800                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1801                 offset += 2;
1802                 size -= 2;
1803         }
1804         while (size >= 1) {
1805                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1806                 offset += 1;
1807                 size -= 1;
1808         }
1809 }
1810
1811 void 
1812 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1813 {
1814         int cur_reg;
1815
1816         if (align == 0)
1817                 align = 4;
1818
1819         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1820         g_assert (size < 10000);
1821
1822         if (align < 4) {
1823                 /* This could be optimized further if neccesary */
1824                 while (size >= 1) {
1825                         cur_reg = alloc_preg (cfg);
1826                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1827                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1828                         doffset += 1;
1829                         soffset += 1;
1830                         size -= 1;
1831                 }
1832         }
1833
1834 #if !NO_UNALIGNED_ACCESS
1835         if (SIZEOF_REGISTER == 8) {
1836                 while (size >= 8) {
1837                         cur_reg = alloc_preg (cfg);
1838                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1839                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1840                         doffset += 8;
1841                         soffset += 8;
1842                         size -= 8;
1843                 }
1844         }       
1845 #endif
1846
1847         while (size >= 4) {
1848                 cur_reg = alloc_preg (cfg);
1849                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1850                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1851                 doffset += 4;
1852                 soffset += 4;
1853                 size -= 4;
1854         }
1855         while (size >= 2) {
1856                 cur_reg = alloc_preg (cfg);
1857                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1858                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1859                 doffset += 2;
1860                 soffset += 2;
1861                 size -= 2;
1862         }
1863         while (size >= 1) {
1864                 cur_reg = alloc_preg (cfg);
1865                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1867                 doffset += 1;
1868                 soffset += 1;
1869                 size -= 1;
1870         }
1871 }
1872
1873 static void
1874 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1875 {
1876         MonoInst *ins, *c;
1877
1878         if (cfg->compile_aot) {
1879                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1880                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1881                 ins->sreg1 = sreg1;
1882                 ins->sreg2 = c->dreg;
1883                 MONO_ADD_INS (cfg->cbb, ins);
1884         } else {
1885                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1886                 ins->sreg1 = sreg1;
1887                 ins->inst_offset = mini_get_tls_offset (tls_key);
1888                 MONO_ADD_INS (cfg->cbb, ins);
1889         }
1890 }
1891
1892 /*
1893  * emit_push_lmf:
1894  *
1895  *   Emit IR to push the current LMF onto the LMF stack.
1896  */
1897 static void
1898 emit_push_lmf (MonoCompile *cfg)
1899 {
1900         /*
1901          * Emit IR to push the LMF:
1902          * lmf_addr = <lmf_addr from tls>
1903          * lmf->lmf_addr = lmf_addr
1904          * lmf->prev_lmf = *lmf_addr
1905          * *lmf_addr = lmf
1906          */
1907         int lmf_reg, prev_lmf_reg;
1908         MonoInst *ins, *lmf_ins;
1909
1910         if (!cfg->lmf_ir)
1911                 return;
1912
1913         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1914                 /* Load current lmf */
1915                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1916                 g_assert (lmf_ins);
1917                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1918                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1919                 lmf_reg = ins->dreg;
1920                 /* Save previous_lmf */
1921                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1922                 /* Set new LMF */
1923                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1924         } else {
1925                 /*
1926                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1927                  */
1928                 if (!cfg->lmf_addr_var)
1929                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1930
1931                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1932                 if (lmf_ins) 
1933                         MONO_ADD_INS (cfg->cbb, lmf_ins);
1934                 else
1935                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1936                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
1937
1938                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1939                 lmf_reg = ins->dreg;
1940
1941                 prev_lmf_reg = alloc_preg (cfg);
1942                 /* Save previous_lmf */
1943                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
1944                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1945                 /* Set new lmf */
1946                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
1947         }
1948 }
1949
1950 /*
1951  * emit_pop_lmf:
1952  *
1953  *   Emit IR to pop the current LMF from the LMF stack.
1954  */
1955 static void
1956 emit_pop_lmf (MonoCompile *cfg)
1957 {
1958         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1959         MonoInst *ins;
1960
1961         if (!cfg->lmf_ir)
1962                 return;
1963
1964         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1965         lmf_reg = ins->dreg;
1966
1967         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1968                 /* Load previous_lmf */
1969                 prev_lmf_reg = alloc_preg (cfg);
1970                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1971                 /* Set new LMF */
1972                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
1973         } else {
1974                 /*
1975                  * Emit IR to pop the LMF:
1976                  * *(lmf->lmf_addr) = lmf->prev_lmf
1977                  */
1978                 /* This could be called before emit_push_lmf () */
1979                 if (!cfg->lmf_addr_var)
1980                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1981                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
1982
1983                 prev_lmf_reg = alloc_preg (cfg);
1984                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1985                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1986         }
1987 }
1988
1989 static int
1990 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1991 {
1992         if (type->byref)
1993                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
1994
1995 handle_enum:
1996         type = mini_get_basic_type_from_generic (gsctx, type);
1997         switch (type->type) {
1998         case MONO_TYPE_VOID:
1999                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2000         case MONO_TYPE_I1:
2001         case MONO_TYPE_U1:
2002         case MONO_TYPE_BOOLEAN:
2003         case MONO_TYPE_I2:
2004         case MONO_TYPE_U2:
2005         case MONO_TYPE_CHAR:
2006         case MONO_TYPE_I4:
2007         case MONO_TYPE_U4:
2008                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2009         case MONO_TYPE_I:
2010         case MONO_TYPE_U:
2011         case MONO_TYPE_PTR:
2012         case MONO_TYPE_FNPTR:
2013                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2014         case MONO_TYPE_CLASS:
2015         case MONO_TYPE_STRING:
2016         case MONO_TYPE_OBJECT:
2017         case MONO_TYPE_SZARRAY:
2018         case MONO_TYPE_ARRAY:    
2019                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2020         case MONO_TYPE_I8:
2021         case MONO_TYPE_U8:
2022                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2023         case MONO_TYPE_R4:
2024         case MONO_TYPE_R8:
2025                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2026         case MONO_TYPE_VALUETYPE:
2027                 if (type->data.klass->enumtype) {
2028                         type = mono_class_enum_basetype (type->data.klass);
2029                         goto handle_enum;
2030                 } else
2031                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2032         case MONO_TYPE_TYPEDBYREF:
2033                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2034         case MONO_TYPE_GENERICINST:
2035                 type = &type->data.generic_class->container_class->byval_arg;
2036                 goto handle_enum;
2037         case MONO_TYPE_VAR:
2038         case MONO_TYPE_MVAR:
2039                 /* gsharedvt */
2040                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2041         default:
2042                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2043         }
2044         return -1;
2045 }
2046
2047 /*
2048  * target_type_is_incompatible:
2049  * @cfg: MonoCompile context
2050  *
2051  * Check that the item @arg on the evaluation stack can be stored
2052  * in the target type (can be a local, or field, etc).
2053  * The cfg arg can be used to check if we need verification or just
2054  * validity checks.
2055  *
2056  * Returns: non-0 value if arg can't be stored on a target.
2057  */
2058 static int
2059 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2060 {
2061         MonoType *simple_type;
2062         MonoClass *klass;
2063
2064         target = mini_replace_type (target);
2065         if (target->byref) {
2066                 /* FIXME: check that the pointed to types match */
2067                 if (arg->type == STACK_MP)
2068                         return arg->klass != mono_class_from_mono_type (target);
2069                 if (arg->type == STACK_PTR)
2070                         return 0;
2071                 return 1;
2072         }
2073
2074         simple_type = mono_type_get_underlying_type (target);
2075         switch (simple_type->type) {
2076         case MONO_TYPE_VOID:
2077                 return 1;
2078         case MONO_TYPE_I1:
2079         case MONO_TYPE_U1:
2080         case MONO_TYPE_BOOLEAN:
2081         case MONO_TYPE_I2:
2082         case MONO_TYPE_U2:
2083         case MONO_TYPE_CHAR:
2084         case MONO_TYPE_I4:
2085         case MONO_TYPE_U4:
2086                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2087                         return 1;
2088                 return 0;
2089         case MONO_TYPE_PTR:
2090                 /* STACK_MP is needed when setting pinned locals */
2091                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2092                         return 1;
2093                 return 0;
2094         case MONO_TYPE_I:
2095         case MONO_TYPE_U:
2096         case MONO_TYPE_FNPTR:
2097                 /* 
2098                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2099                  * in native int. (#688008).
2100                  */
2101                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2102                         return 1;
2103                 return 0;
2104         case MONO_TYPE_CLASS:
2105         case MONO_TYPE_STRING:
2106         case MONO_TYPE_OBJECT:
2107         case MONO_TYPE_SZARRAY:
2108         case MONO_TYPE_ARRAY:    
2109                 if (arg->type != STACK_OBJ)
2110                         return 1;
2111                 /* FIXME: check type compatibility */
2112                 return 0;
2113         case MONO_TYPE_I8:
2114         case MONO_TYPE_U8:
2115                 if (arg->type != STACK_I8)
2116                         return 1;
2117                 return 0;
2118         case MONO_TYPE_R4:
2119         case MONO_TYPE_R8:
2120                 if (arg->type != STACK_R8)
2121                         return 1;
2122                 return 0;
2123         case MONO_TYPE_VALUETYPE:
2124                 if (arg->type != STACK_VTYPE)
2125                         return 1;
2126                 klass = mono_class_from_mono_type (simple_type);
2127                 if (klass != arg->klass)
2128                         return 1;
2129                 return 0;
2130         case MONO_TYPE_TYPEDBYREF:
2131                 if (arg->type != STACK_VTYPE)
2132                         return 1;
2133                 klass = mono_class_from_mono_type (simple_type);
2134                 if (klass != arg->klass)
2135                         return 1;
2136                 return 0;
2137         case MONO_TYPE_GENERICINST:
2138                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2139                         if (arg->type != STACK_VTYPE)
2140                                 return 1;
2141                         klass = mono_class_from_mono_type (simple_type);
2142                         if (klass != arg->klass)
2143                                 return 1;
2144                         return 0;
2145                 } else {
2146                         if (arg->type != STACK_OBJ)
2147                                 return 1;
2148                         /* FIXME: check type compatibility */
2149                         return 0;
2150                 }
2151         case MONO_TYPE_VAR:
2152         case MONO_TYPE_MVAR:
2153                 g_assert (cfg->generic_sharing_context);
2154                 if (mini_type_var_is_vt (cfg, simple_type)) {
2155                         if (arg->type != STACK_VTYPE)
2156                                 return 1;
2157                 } else {
2158                         if (arg->type != STACK_OBJ)
2159                                 return 1;
2160                 }
2161                 return 0;
2162         default:
2163                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2164         }
2165         return 1;
2166 }
2167
2168 /*
2169  * Prepare arguments for passing to a function call.
2170  * Return a non-zero value if the arguments can't be passed to the given
2171  * signature.
2172  * The type checks are not yet complete and some conversions may need
2173  * casts on 32 or 64 bit architectures.
2174  *
2175  * FIXME: implement this using target_type_is_incompatible ()
2176  */
2177 static int
2178 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2179 {
2180         MonoType *simple_type;
2181         int i;
2182
2183         if (sig->hasthis) {
2184                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2185                         return 1;
2186                 args++;
2187         }
2188         for (i = 0; i < sig->param_count; ++i) {
2189                 if (sig->params [i]->byref) {
2190                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2191                                 return 1;
2192                         continue;
2193                 }
2194                 simple_type = sig->params [i];
2195                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2196 handle_enum:
2197                 switch (simple_type->type) {
2198                 case MONO_TYPE_VOID:
2199                         return 1;
2200                         continue;
2201                 case MONO_TYPE_I1:
2202                 case MONO_TYPE_U1:
2203                 case MONO_TYPE_BOOLEAN:
2204                 case MONO_TYPE_I2:
2205                 case MONO_TYPE_U2:
2206                 case MONO_TYPE_CHAR:
2207                 case MONO_TYPE_I4:
2208                 case MONO_TYPE_U4:
2209                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2210                                 return 1;
2211                         continue;
2212                 case MONO_TYPE_I:
2213                 case MONO_TYPE_U:
2214                 case MONO_TYPE_PTR:
2215                 case MONO_TYPE_FNPTR:
2216                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2217                                 return 1;
2218                         continue;
2219                 case MONO_TYPE_CLASS:
2220                 case MONO_TYPE_STRING:
2221                 case MONO_TYPE_OBJECT:
2222                 case MONO_TYPE_SZARRAY:
2223                 case MONO_TYPE_ARRAY:    
2224                         if (args [i]->type != STACK_OBJ)
2225                                 return 1;
2226                         continue;
2227                 case MONO_TYPE_I8:
2228                 case MONO_TYPE_U8:
2229                         if (args [i]->type != STACK_I8)
2230                                 return 1;
2231                         continue;
2232                 case MONO_TYPE_R4:
2233                 case MONO_TYPE_R8:
2234                         if (args [i]->type != STACK_R8)
2235                                 return 1;
2236                         continue;
2237                 case MONO_TYPE_VALUETYPE:
2238                         if (simple_type->data.klass->enumtype) {
2239                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2240                                 goto handle_enum;
2241                         }
2242                         if (args [i]->type != STACK_VTYPE)
2243                                 return 1;
2244                         continue;
2245                 case MONO_TYPE_TYPEDBYREF:
2246                         if (args [i]->type != STACK_VTYPE)
2247                                 return 1;
2248                         continue;
2249                 case MONO_TYPE_GENERICINST:
2250                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2251                         goto handle_enum;
2252                 case MONO_TYPE_VAR:
2253                 case MONO_TYPE_MVAR:
2254                         /* gsharedvt */
2255                         if (args [i]->type != STACK_VTYPE)
2256                                 return 1;
2257                         continue;
2258                 default:
2259                         g_error ("unknown type 0x%02x in check_call_signature",
2260                                  simple_type->type);
2261                 }
2262         }
2263         return 0;
2264 }
2265
2266 static int
2267 callvirt_to_call (int opcode)
2268 {
2269         switch (opcode) {
2270         case OP_CALL_MEMBASE:
2271                 return OP_CALL;
2272         case OP_VOIDCALL_MEMBASE:
2273                 return OP_VOIDCALL;
2274         case OP_FCALL_MEMBASE:
2275                 return OP_FCALL;
2276         case OP_VCALL_MEMBASE:
2277                 return OP_VCALL;
2278         case OP_LCALL_MEMBASE:
2279                 return OP_LCALL;
2280         default:
2281                 g_assert_not_reached ();
2282         }
2283
2284         return -1;
2285 }
2286
2287 #ifdef MONO_ARCH_HAVE_IMT
2288 /* Either METHOD or IMT_ARG needs to be set */
2289 static void
2290 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2291 {
2292         int method_reg;
2293
2294         if (COMPILE_LLVM (cfg)) {
2295                 method_reg = alloc_preg (cfg);
2296
2297                 if (imt_arg) {
2298                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2299                 } else if (cfg->compile_aot) {
2300                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2301                 } else {
2302                         MonoInst *ins;
2303                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2304                         ins->inst_p0 = method;
2305                         ins->dreg = method_reg;
2306                         MONO_ADD_INS (cfg->cbb, ins);
2307                 }
2308
2309 #ifdef ENABLE_LLVM
2310                 call->imt_arg_reg = method_reg;
2311 #endif
2312 #ifdef MONO_ARCH_IMT_REG
2313         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2314 #else
2315         /* Need this to keep the IMT arg alive */
2316         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2317 #endif
2318                 return;
2319         }
2320
2321 #ifdef MONO_ARCH_IMT_REG
2322         method_reg = alloc_preg (cfg);
2323
2324         if (imt_arg) {
2325                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2326         } else if (cfg->compile_aot) {
2327                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2328         } else {
2329                 MonoInst *ins;
2330                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2331                 ins->inst_p0 = method;
2332                 ins->dreg = method_reg;
2333                 MONO_ADD_INS (cfg->cbb, ins);
2334         }
2335
2336         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2337 #else
2338         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2339 #endif
2340 }
2341 #endif
2342
2343 static MonoJumpInfo *
2344 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2345 {
2346         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2347
2348         ji->ip.i = ip;
2349         ji->type = type;
2350         ji->data.target = target;
2351
2352         return ji;
2353 }
2354
2355 static int
2356 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2357 {
2358         if (cfg->generic_sharing_context)
2359                 return mono_class_check_context_used (klass);
2360         else
2361                 return 0;
2362 }
2363
2364 static int
2365 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2366 {
2367         if (cfg->generic_sharing_context)
2368                 return mono_method_check_context_used (method);
2369         else
2370                 return 0;
2371 }
2372
2373 /*
2374  * check_method_sharing:
2375  *
2376  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2377  */
2378 static void
2379 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2380 {
2381         gboolean pass_vtable = FALSE;
2382         gboolean pass_mrgctx = FALSE;
2383
2384         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2385                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2386                 gboolean sharable = FALSE;
2387
2388                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2389                         sharable = TRUE;
2390                 } else {
2391                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2392                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2393                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2394
2395                         sharable = sharing_enabled && context_sharable;
2396                 }
2397
2398                 /*
2399                  * Pass vtable iff target method might
2400                  * be shared, which means that sharing
2401                  * is enabled for its class and its
2402                  * context is sharable (and it's not a
2403                  * generic method).
2404                  */
2405                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2406                         pass_vtable = TRUE;
2407         }
2408
2409         if (mini_method_get_context (cmethod) &&
2410                 mini_method_get_context (cmethod)->method_inst) {
2411                 g_assert (!pass_vtable);
2412
2413                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2414                         pass_mrgctx = TRUE;
2415                 } else {
2416                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2417                         MonoGenericContext *context = mini_method_get_context (cmethod);
2418                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2419
2420                         if (sharing_enabled && context_sharable)
2421                                 pass_mrgctx = TRUE;
2422                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2423                                 pass_mrgctx = TRUE;
2424                 }
2425         }
2426
2427         if (out_pass_vtable)
2428                 *out_pass_vtable = pass_vtable;
2429         if (out_pass_mrgctx)
2430                 *out_pass_mrgctx = pass_mrgctx;
2431 }
2432
2433 inline static MonoCallInst *
2434 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2435                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2436 {
2437         MonoType *sig_ret;
2438         MonoCallInst *call;
2439 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2440         int i;
2441 #endif
2442
2443         if (tail)
2444                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2445         else
2446                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2447
2448         call->args = args;
2449         call->signature = sig;
2450         call->rgctx_reg = rgctx;
2451         sig_ret = mini_replace_type (sig->ret);
2452
2453         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2454
2455         if (tail) {
2456                 if (mini_type_is_vtype (cfg, sig_ret)) {
2457                         call->vret_var = cfg->vret_addr;
2458                         //g_assert_not_reached ();
2459                 }
2460         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2461                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2462                 MonoInst *loada;
2463
2464                 temp->backend.is_pinvoke = sig->pinvoke;
2465
2466                 /*
2467                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2468                  * address of return value to increase optimization opportunities.
2469                  * Before vtype decomposition, the dreg of the call ins itself represents the
2470                  * fact the call modifies the return value. After decomposition, the call will
2471                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2472                  * will be transformed into an LDADDR.
2473                  */
2474                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2475                 loada->dreg = alloc_preg (cfg);
2476                 loada->inst_p0 = temp;
2477                 /* We reference the call too since call->dreg could change during optimization */
2478                 loada->inst_p1 = call;
2479                 MONO_ADD_INS (cfg->cbb, loada);
2480
2481                 call->inst.dreg = temp->dreg;
2482
2483                 call->vret_var = loada;
2484         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2485                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2486
2487 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2488         if (COMPILE_SOFT_FLOAT (cfg)) {
2489                 /* 
2490                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2491                  * an icall, but that cannot be done during the call sequence since it would clobber
2492                  * the call registers + the stack. So we do it before emitting the call.
2493                  */
2494                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2495                         MonoType *t;
2496                         MonoInst *in = call->args [i];
2497
2498                         if (i >= sig->hasthis)
2499                                 t = sig->params [i - sig->hasthis];
2500                         else
2501                                 t = &mono_defaults.int_class->byval_arg;
2502                         t = mono_type_get_underlying_type (t);
2503
2504                         if (!t->byref && t->type == MONO_TYPE_R4) {
2505                                 MonoInst *iargs [1];
2506                                 MonoInst *conv;
2507
2508                                 iargs [0] = in;
2509                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2510
2511                                 /* The result will be in an int vreg */
2512                                 call->args [i] = conv;
2513                         }
2514                 }
2515         }
2516 #endif
2517
2518         call->need_unbox_trampoline = unbox_trampoline;
2519
2520 #ifdef ENABLE_LLVM
2521         if (COMPILE_LLVM (cfg))
2522                 mono_llvm_emit_call (cfg, call);
2523         else
2524                 mono_arch_emit_call (cfg, call);
2525 #else
2526         mono_arch_emit_call (cfg, call);
2527 #endif
2528
2529         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2530         cfg->flags |= MONO_CFG_HAS_CALLS;
2531         
2532         return call;
2533 }
2534
2535 static void
2536 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2537 {
2538 #ifdef MONO_ARCH_RGCTX_REG
2539         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2540         cfg->uses_rgctx_reg = TRUE;
2541         call->rgctx_reg = TRUE;
2542 #ifdef ENABLE_LLVM
2543         call->rgctx_arg_reg = rgctx_reg;
2544 #endif
2545 #else
2546         NOT_IMPLEMENTED;
2547 #endif
2548 }       
2549
2550 inline static MonoInst*
2551 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2552 {
2553         MonoCallInst *call;
2554         int rgctx_reg = -1;
2555
2556         if (rgctx_arg) {
2557                 rgctx_reg = mono_alloc_preg (cfg);
2558                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2559         }
2560
2561         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2562
2563         call->inst.sreg1 = addr->dreg;
2564
2565         if (imt_arg)
2566                 emit_imt_argument (cfg, call, NULL, imt_arg);
2567
2568         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2569
2570         if (rgctx_arg)
2571                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2572
2573         return (MonoInst*)call;
2574 }
2575
2576 static MonoInst*
2577 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2578
2579 static MonoInst*
2580 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2581 static MonoInst*
2582 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2583
2584 static MonoInst*
2585 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2586                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2587 {
2588 #ifndef DISABLE_REMOTING
2589         gboolean might_be_remote = FALSE;
2590 #endif
2591         gboolean virtual = this != NULL;
2592         gboolean enable_for_aot = TRUE;
2593         int context_used;
2594         MonoCallInst *call;
2595         int rgctx_reg = 0;
2596         gboolean need_unbox_trampoline;
2597
2598         if (!sig)
2599                 sig = mono_method_signature (method);
2600
2601         if (rgctx_arg) {
2602                 rgctx_reg = mono_alloc_preg (cfg);
2603                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2604         }
2605
2606         if (method->string_ctor) {
2607                 /* Create the real signature */
2608                 /* FIXME: Cache these */
2609                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2610                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2611
2612                 sig = ctor_sig;
2613         }
2614
2615         context_used = mini_method_check_context_used (cfg, method);
2616
2617 #ifndef DISABLE_REMOTING
2618         might_be_remote = this && sig->hasthis &&
2619                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2620                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2621
2622         if (might_be_remote && context_used) {
2623                 MonoInst *addr;
2624
2625                 g_assert (cfg->generic_sharing_context);
2626
2627                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2628
2629                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2630         }
2631 #endif
2632
2633         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2634
2635         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2636
2637 #ifndef DISABLE_REMOTING
2638         if (might_be_remote)
2639                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2640         else
2641 #endif
2642                 call->method = method;
2643         call->inst.flags |= MONO_INST_HAS_METHOD;
2644         call->inst.inst_left = this;
2645         call->tail_call = tail;
2646
2647         if (virtual) {
2648                 int vtable_reg, slot_reg, this_reg;
2649                 int offset;
2650
2651                 this_reg = this->dreg;
2652
2653                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2654                         MonoInst *dummy_use;
2655
2656                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2657
2658                         /* Make a call to delegate->invoke_impl */
2659                         call->inst.inst_basereg = this_reg;
2660                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2661                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2662
2663                         /* We must emit a dummy use here because the delegate trampoline will
2664                         replace the 'this' argument with the delegate target making this activation
2665                         no longer a root for the delegate.
2666                         This is an issue for delegates that target collectible code such as dynamic
2667                         methods of GC'able assemblies.
2668
2669                         For a test case look into #667921.
2670
2671                         FIXME: a dummy use is not the best way to do it as the local register allocator
2672                         will put it on a caller save register and spil it around the call. 
2673                         Ideally, we would either put it on a callee save register or only do the store part.  
2674                          */
2675                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2676
2677                         return (MonoInst*)call;
2678                 }
2679
2680                 if ((!cfg->compile_aot || enable_for_aot) && 
2681                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2682                          (MONO_METHOD_IS_FINAL (method) &&
2683                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2684                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2685                         /* 
2686                          * the method is not virtual, we just need to ensure this is not null
2687                          * and then we can call the method directly.
2688                          */
2689 #ifndef DISABLE_REMOTING
2690                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2691                                 /* 
2692                                  * The check above ensures method is not gshared, this is needed since
2693                                  * gshared methods can't have wrappers.
2694                                  */
2695                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2696                         }
2697 #endif
2698
2699                         if (!method->string_ctor)
2700                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2701
2702                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2703                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2704                         /*
2705                          * the method is virtual, but we can statically dispatch since either
2706                          * it's class or the method itself are sealed.
2707                          * But first we need to ensure it's not a null reference.
2708                          */
2709                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2710
2711                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2712                 } else {
2713                         vtable_reg = alloc_preg (cfg);
2714                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2715                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2716                                 slot_reg = -1;
2717 #ifdef MONO_ARCH_HAVE_IMT
2718                                 if (mono_use_imt) {
2719                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2720                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2721                                         slot_reg = vtable_reg;
2722                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2723                                 }
2724 #endif
2725                                 if (slot_reg == -1) {
2726                                         slot_reg = alloc_preg (cfg);
2727                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2728                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2729                                 }
2730                         } else {
2731                                 slot_reg = vtable_reg;
2732                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2733                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2734 #ifdef MONO_ARCH_HAVE_IMT
2735                                 if (imt_arg) {
2736                                         g_assert (mono_method_signature (method)->generic_param_count);
2737                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2738                                 }
2739 #endif
2740                         }
2741
2742                         call->inst.sreg1 = slot_reg;
2743                         call->inst.inst_offset = offset;
2744                         call->virtual = TRUE;
2745                 }
2746         }
2747
2748         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2749
2750         if (rgctx_arg)
2751                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2752
2753         return (MonoInst*)call;
2754 }
2755
2756 MonoInst*
2757 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2758 {
2759         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2760 }
2761
2762 MonoInst*
2763 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2764                                            MonoInst **args)
2765 {
2766         MonoCallInst *call;
2767
2768         g_assert (sig);
2769
2770         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2771         call->fptr = func;
2772
2773         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2774
2775         return (MonoInst*)call;
2776 }
2777
2778 MonoInst*
2779 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2780 {
2781         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2782
2783         g_assert (info);
2784
2785         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2786 }
2787
2788 /*
2789  * mono_emit_abs_call:
2790  *
2791  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2792  */
2793 inline static MonoInst*
2794 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2795                                         MonoMethodSignature *sig, MonoInst **args)
2796 {
2797         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2798         MonoInst *ins;
2799
2800         /* 
2801          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2802          * handle it.
2803          */
2804         if (cfg->abs_patches == NULL)
2805                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2806         g_hash_table_insert (cfg->abs_patches, ji, ji);
2807         ins = mono_emit_native_call (cfg, ji, sig, args);
2808         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2809         return ins;
2810 }
2811  
2812 static MonoInst*
2813 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2814 {
2815         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2816                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2817                         int widen_op = -1;
2818
2819                         /* 
2820                          * Native code might return non register sized integers 
2821                          * without initializing the upper bits.
2822                          */
2823                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2824                         case OP_LOADI1_MEMBASE:
2825                                 widen_op = OP_ICONV_TO_I1;
2826                                 break;
2827                         case OP_LOADU1_MEMBASE:
2828                                 widen_op = OP_ICONV_TO_U1;
2829                                 break;
2830                         case OP_LOADI2_MEMBASE:
2831                                 widen_op = OP_ICONV_TO_I2;
2832                                 break;
2833                         case OP_LOADU2_MEMBASE:
2834                                 widen_op = OP_ICONV_TO_U2;
2835                                 break;
2836                         default:
2837                                 break;
2838                         }
2839
2840                         if (widen_op != -1) {
2841                                 int dreg = alloc_preg (cfg);
2842                                 MonoInst *widen;
2843
2844                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2845                                 widen->type = ins->type;
2846                                 ins = widen;
2847                         }
2848                 }
2849         }
2850
2851         return ins;
2852 }
2853
2854 static MonoMethod*
2855 get_memcpy_method (void)
2856 {
2857         static MonoMethod *memcpy_method = NULL;
2858         if (!memcpy_method) {
2859                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2860                 if (!memcpy_method)
2861                         g_error ("Old corlib found. Install a new one");
2862         }
2863         return memcpy_method;
2864 }
2865
2866 static void
2867 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2868 {
2869         MonoClassField *field;
2870         gpointer iter = NULL;
2871
2872         while ((field = mono_class_get_fields (klass, &iter))) {
2873                 int foffset;
2874
2875                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2876                         continue;
2877                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2878                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2879                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2880                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2881                 } else {
2882                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2883                         if (field_class->has_references)
2884                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2885                 }
2886         }
2887 }
2888
2889 static void
2890 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2891 {
2892         int card_table_shift_bits;
2893         gpointer card_table_mask;
2894         guint8 *card_table;
2895         MonoInst *dummy_use;
2896         int nursery_shift_bits;
2897         size_t nursery_size;
2898         gboolean has_card_table_wb = FALSE;
2899
2900         if (!cfg->gen_write_barriers)
2901                 return;
2902
2903         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2904
2905         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2906
2907 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2908         has_card_table_wb = TRUE;
2909 #endif
2910
2911         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
2912                 MonoInst *wbarrier;
2913
2914                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2915                 wbarrier->sreg1 = ptr->dreg;
2916                 wbarrier->sreg2 = value->dreg;
2917                 MONO_ADD_INS (cfg->cbb, wbarrier);
2918         } else if (card_table) {
2919                 int offset_reg = alloc_preg (cfg);
2920                 int card_reg  = alloc_preg (cfg);
2921                 MonoInst *ins;
2922
2923                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2924                 if (card_table_mask)
2925                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2926
2927                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2928                  * IMM's larger than 32bits.
2929                  */
2930                 if (cfg->compile_aot) {
2931                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2932                 } else {
2933                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2934                         ins->inst_p0 = card_table;
2935                         ins->dreg = card_reg;
2936                         MONO_ADD_INS (cfg->cbb, ins);
2937                 }
2938
2939                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2940                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2941         } else {
2942                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2943                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2944         }
2945
2946         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2947 }
2948
2949 static gboolean
2950 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2951 {
2952         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2953         unsigned need_wb = 0;
2954
2955         if (align == 0)
2956                 align = 4;
2957
2958         /*types with references can't have alignment smaller than sizeof(void*) */
2959         if (align < SIZEOF_VOID_P)
2960                 return FALSE;
2961
2962         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2963         if (size > 32 * SIZEOF_VOID_P)
2964                 return FALSE;
2965
2966         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
2967
2968         /* We don't unroll more than 5 stores to avoid code bloat. */
2969         if (size > 5 * SIZEOF_VOID_P) {
2970                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2971                 size += (SIZEOF_VOID_P - 1);
2972                 size &= ~(SIZEOF_VOID_P - 1);
2973
2974                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2975                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2976                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2977                 return TRUE;
2978         }
2979
2980         destreg = iargs [0]->dreg;
2981         srcreg = iargs [1]->dreg;
2982         offset = 0;
2983
2984         dest_ptr_reg = alloc_preg (cfg);
2985         tmp_reg = alloc_preg (cfg);
2986
2987         /*tmp = dreg*/
2988         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
2989
2990         while (size >= SIZEOF_VOID_P) {
2991                 MonoInst *load_inst;
2992                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
2993                 load_inst->dreg = tmp_reg;
2994                 load_inst->inst_basereg = srcreg;
2995                 load_inst->inst_offset = offset;
2996                 MONO_ADD_INS (cfg->cbb, load_inst);
2997
2998                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
2999
3000                 if (need_wb & 0x1)
3001                         emit_write_barrier (cfg, iargs [0], load_inst);
3002
3003                 offset += SIZEOF_VOID_P;
3004                 size -= SIZEOF_VOID_P;
3005                 need_wb >>= 1;
3006
3007                 /*tmp += sizeof (void*)*/
3008                 if (size >= SIZEOF_VOID_P) {
3009                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3010                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3011                 }
3012         }
3013
3014         /* Those cannot be references since size < sizeof (void*) */
3015         while (size >= 4) {
3016                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3017                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3018                 offset += 4;
3019                 size -= 4;
3020         }
3021
3022         while (size >= 2) {
3023                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3024                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3025                 offset += 2;
3026                 size -= 2;
3027         }
3028
3029         while (size >= 1) {
3030                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3031                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3032                 offset += 1;
3033                 size -= 1;
3034         }
3035
3036         return TRUE;
3037 }
3038
3039 /*
3040  * Emit code to copy a valuetype of type @klass whose address is stored in
3041  * @src->dreg to memory whose address is stored at @dest->dreg.
3042  */
3043 void
3044 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3045 {
3046         MonoInst *iargs [4];
3047         int context_used, n;
3048         guint32 align = 0;
3049         MonoMethod *memcpy_method;
3050         MonoInst *size_ins = NULL;
3051         MonoInst *memcpy_ins = NULL;
3052
3053         g_assert (klass);
3054         /*
3055          * This check breaks with spilled vars... need to handle it during verification anyway.
3056          * g_assert (klass && klass == src->klass && klass == dest->klass);
3057          */
3058
3059         if (mini_is_gsharedvt_klass (cfg, klass)) {
3060                 g_assert (!native);
3061                 context_used = mini_class_check_context_used (cfg, klass);
3062                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3063                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3064         }
3065
3066         if (native)
3067                 n = mono_class_native_size (klass, &align);
3068         else
3069                 n = mono_class_value_size (klass, &align);
3070
3071         /* if native is true there should be no references in the struct */
3072         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3073                 /* Avoid barriers when storing to the stack */
3074                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3075                           (dest->opcode == OP_LDADDR))) {
3076                         int context_used;
3077
3078                         iargs [0] = dest;
3079                         iargs [1] = src;
3080
3081                         context_used = mini_class_check_context_used (cfg, klass);
3082
3083                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3084                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3085                                 return;
3086                         } else if (context_used) {
3087                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3088                         }  else {
3089                                 if (cfg->compile_aot) {
3090                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3091                                 } else {
3092                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3093                                         mono_class_compute_gc_descriptor (klass);
3094                                 }
3095                         }
3096
3097                         if (size_ins)
3098                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3099                         else
3100                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3101                         return;
3102                 }
3103         }
3104
3105         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3106                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3107                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3108         } else {
3109                 iargs [0] = dest;
3110                 iargs [1] = src;
3111                 if (size_ins)
3112                         iargs [2] = size_ins;
3113                 else
3114                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3115                 
3116                 memcpy_method = get_memcpy_method ();
3117                 if (memcpy_ins)
3118                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3119                 else
3120                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3121         }
3122 }
3123
3124 static MonoMethod*
3125 get_memset_method (void)
3126 {
3127         static MonoMethod *memset_method = NULL;
3128         if (!memset_method) {
3129                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3130                 if (!memset_method)
3131                         g_error ("Old corlib found. Install a new one");
3132         }
3133         return memset_method;
3134 }
3135
3136 void
3137 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3138 {
3139         MonoInst *iargs [3];
3140         int n, context_used;
3141         guint32 align;
3142         MonoMethod *memset_method;
3143         MonoInst *size_ins = NULL;
3144         MonoInst *bzero_ins = NULL;
3145         static MonoMethod *bzero_method;
3146
3147         /* FIXME: Optimize this for the case when dest is an LDADDR */
3148
3149         mono_class_init (klass);
3150         if (mini_is_gsharedvt_klass (cfg, klass)) {
3151                 context_used = mini_class_check_context_used (cfg, klass);
3152                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3153                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3154                 if (!bzero_method)
3155                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3156                 g_assert (bzero_method);
3157                 iargs [0] = dest;
3158                 iargs [1] = size_ins;
3159                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3160                 return;
3161         }
3162
3163         n = mono_class_value_size (klass, &align);
3164
3165         if (n <= sizeof (gpointer) * 5) {
3166                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3167         }
3168         else {
3169                 memset_method = get_memset_method ();
3170                 iargs [0] = dest;
3171                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3172                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3173                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3174         }
3175 }
3176
3177 static MonoInst*
3178 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3179 {
3180         MonoInst *this = NULL;
3181
3182         g_assert (cfg->generic_sharing_context);
3183
3184         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3185                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3186                         !method->klass->valuetype)
3187                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3188
3189         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3190                 MonoInst *mrgctx_loc, *mrgctx_var;
3191
3192                 g_assert (!this);
3193                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3194
3195                 mrgctx_loc = mono_get_vtable_var (cfg);
3196                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3197
3198                 return mrgctx_var;
3199         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3200                 MonoInst *vtable_loc, *vtable_var;
3201
3202                 g_assert (!this);
3203
3204                 vtable_loc = mono_get_vtable_var (cfg);
3205                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3206
3207                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3208                         MonoInst *mrgctx_var = vtable_var;
3209                         int vtable_reg;
3210
3211                         vtable_reg = alloc_preg (cfg);
3212                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3213                         vtable_var->type = STACK_PTR;
3214                 }
3215
3216                 return vtable_var;
3217         } else {
3218                 MonoInst *ins;
3219                 int vtable_reg;
3220         
3221                 vtable_reg = alloc_preg (cfg);
3222                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3223                 return ins;
3224         }
3225 }
3226
3227 static MonoJumpInfoRgctxEntry *
3228 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3229 {
3230         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3231         res->method = method;
3232         res->in_mrgctx = in_mrgctx;
3233         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3234         res->data->type = patch_type;
3235         res->data->data.target = patch_data;
3236         res->info_type = info_type;
3237
3238         return res;
3239 }
3240
3241 static inline MonoInst*
3242 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3243 {
3244         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3245 }
3246
3247 static MonoInst*
3248 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3249                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3250 {
3251         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);
3252         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3253
3254         return emit_rgctx_fetch (cfg, rgctx, entry);
3255 }
3256
3257 static MonoInst*
3258 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3259                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3260 {
3261         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);
3262         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3263
3264         return emit_rgctx_fetch (cfg, rgctx, entry);
3265 }
3266
3267 static MonoInst*
3268 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3269                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3270 {
3271         MonoJumpInfoGSharedVtCall *call_info;
3272         MonoJumpInfoRgctxEntry *entry;
3273         MonoInst *rgctx;
3274
3275         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3276         call_info->sig = sig;
3277         call_info->method = cmethod;
3278
3279         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);
3280         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3281
3282         return emit_rgctx_fetch (cfg, rgctx, entry);
3283 }
3284
3285
3286 static MonoInst*
3287 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3288                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3289 {
3290         MonoJumpInfoRgctxEntry *entry;
3291         MonoInst *rgctx;
3292
3293         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);
3294         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3295
3296         return emit_rgctx_fetch (cfg, rgctx, entry);
3297 }
3298
3299 /*
3300  * emit_get_rgctx_method:
3301  *
3302  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3303  * normal constants, else emit a load from the rgctx.
3304  */
3305 static MonoInst*
3306 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3307                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3308 {
3309         if (!context_used) {
3310                 MonoInst *ins;
3311
3312                 switch (rgctx_type) {
3313                 case MONO_RGCTX_INFO_METHOD:
3314                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3315                         return ins;
3316                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3317                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3318                         return ins;
3319                 default:
3320                         g_assert_not_reached ();
3321                 }
3322         } else {
3323                 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);
3324                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3325
3326                 return emit_rgctx_fetch (cfg, rgctx, entry);
3327         }
3328 }
3329
3330 static MonoInst*
3331 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3332                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3333 {
3334         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);
3335         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3336
3337         return emit_rgctx_fetch (cfg, rgctx, entry);
3338 }
3339
3340 static int
3341 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3342 {
3343         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3344         MonoRuntimeGenericContextInfoTemplate *template;
3345         int i, idx;
3346
3347         g_assert (info);
3348
3349         for (i = 0; i < info->entries->len; ++i) {
3350                 MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (info->entries, i);
3351
3352                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3353                         return i;
3354         }
3355
3356         template = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate));
3357         template->info_type = rgctx_type;
3358         template->data = data;
3359
3360         idx = info->entries->len;
3361
3362         g_ptr_array_add (info->entries, template);
3363
3364         return idx;
3365 }
3366
3367 /*
3368  * emit_get_gsharedvt_info:
3369  *
3370  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3371  */
3372 static MonoInst*
3373 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3374 {
3375         MonoInst *ins;
3376         int idx, dreg;
3377
3378         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3379         /* Load info->entries [idx] */
3380         dreg = alloc_preg (cfg);
3381         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3382
3383         return ins;
3384 }
3385
3386 static MonoInst*
3387 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3388 {
3389         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3390 }
3391
3392 /*
3393  * On return the caller must check @klass for load errors.
3394  */
3395 static void
3396 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3397 {
3398         MonoInst *vtable_arg;
3399         MonoCallInst *call;
3400         int context_used;
3401
3402         context_used = mini_class_check_context_used (cfg, klass);
3403
3404         if (context_used) {
3405                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3406                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3407         } else {
3408                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3409
3410                 if (!vtable)
3411                         return;
3412                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3413         }
3414
3415         if (COMPILE_LLVM (cfg))
3416                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3417         else
3418                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3419 #ifdef MONO_ARCH_VTABLE_REG
3420         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3421         cfg->uses_vtable_reg = TRUE;
3422 #else
3423         NOT_IMPLEMENTED;
3424 #endif
3425 }
3426
3427 static void
3428 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3429 {
3430         MonoInst *ins;
3431
3432         if (cfg->gen_seq_points && cfg->method == method) {
3433                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3434                 if (nonempty_stack)
3435                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3436                 MONO_ADD_INS (cfg->cbb, ins);
3437         }
3438 }
3439
3440 static void
3441 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3442 {
3443         if (mini_get_debug_options ()->better_cast_details) {
3444                 int to_klass_reg = alloc_preg (cfg);
3445                 int vtable_reg = alloc_preg (cfg);
3446                 int klass_reg = alloc_preg (cfg);
3447                 MonoBasicBlock *is_null_bb = NULL;
3448                 MonoInst *tls_get;
3449
3450                 if (null_check) {
3451                         NEW_BBLOCK (cfg, is_null_bb);
3452
3453                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3454                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3455                 }
3456
3457                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3458                 if (!tls_get) {
3459                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3460                         exit (1);
3461                 }
3462
3463                 MONO_ADD_INS (cfg->cbb, tls_get);
3464                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3465                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3466
3467                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3468                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3469                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3470
3471                 if (null_check) {
3472                         MONO_START_BB (cfg, is_null_bb);
3473                         if (out_bblock)
3474                                 *out_bblock = cfg->cbb;
3475                 }
3476         }
3477 }
3478
3479 static void
3480 reset_cast_details (MonoCompile *cfg)
3481 {
3482         /* Reset the variables holding the cast details */
3483         if (mini_get_debug_options ()->better_cast_details) {
3484                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3485
3486                 MONO_ADD_INS (cfg->cbb, tls_get);
3487                 /* It is enough to reset the from field */
3488                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3489         }
3490 }
3491
3492 /*
3493  * On return the caller must check @array_class for load errors
3494  */
3495 static void
3496 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3497 {
3498         int vtable_reg = alloc_preg (cfg);
3499         int context_used;
3500
3501         context_used = mini_class_check_context_used (cfg, array_class);
3502
3503         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3504
3505         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3506
3507         if (cfg->opt & MONO_OPT_SHARED) {
3508                 int class_reg = alloc_preg (cfg);
3509                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3510                 if (cfg->compile_aot) {
3511                         int klass_reg = alloc_preg (cfg);
3512                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3513                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3514                 } else {
3515                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3516                 }
3517         } else if (context_used) {
3518                 MonoInst *vtable_ins;
3519
3520                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3521                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3522         } else {
3523                 if (cfg->compile_aot) {
3524                         int vt_reg;
3525                         MonoVTable *vtable;
3526
3527                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3528                                 return;
3529                         vt_reg = alloc_preg (cfg);
3530                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3531                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3532                 } else {
3533                         MonoVTable *vtable;
3534                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3535                                 return;
3536                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3537                 }
3538         }
3539         
3540         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3541
3542         reset_cast_details (cfg);
3543 }
3544
3545 /**
3546  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3547  * generic code is generated.
3548  */
3549 static MonoInst*
3550 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3551 {
3552         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3553
3554         if (context_used) {
3555                 MonoInst *rgctx, *addr;
3556
3557                 /* FIXME: What if the class is shared?  We might not
3558                    have to get the address of the method from the
3559                    RGCTX. */
3560                 addr = emit_get_rgctx_method (cfg, context_used, method,
3561                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3562
3563                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3564
3565                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3566         } else {
3567                 gboolean pass_vtable, pass_mrgctx;
3568                 MonoInst *rgctx_arg = NULL;
3569
3570                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3571                 g_assert (!pass_mrgctx);
3572
3573                 if (pass_vtable) {
3574                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3575
3576                         g_assert (vtable);
3577                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3578                 }
3579
3580                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3581         }
3582 }
3583
3584 static MonoInst*
3585 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3586 {
3587         MonoInst *add;
3588         int obj_reg;
3589         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3590         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3591         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3592         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3593
3594         obj_reg = sp [0]->dreg;
3595         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3596         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3597
3598         /* FIXME: generics */
3599         g_assert (klass->rank == 0);
3600                         
3601         // Check rank == 0
3602         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3603         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3604
3605         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3606         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3607
3608         if (context_used) {
3609                 MonoInst *element_class;
3610
3611                 /* This assertion is from the unboxcast insn */
3612                 g_assert (klass->rank == 0);
3613
3614                 element_class = emit_get_rgctx_klass (cfg, context_used,
3615                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3616
3617                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3618                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3619         } else {
3620                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3621                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3622                 reset_cast_details (cfg);
3623         }
3624
3625         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3626         MONO_ADD_INS (cfg->cbb, add);
3627         add->type = STACK_MP;
3628         add->klass = klass;
3629
3630         return add;
3631 }
3632
3633 static MonoInst*
3634 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3635 {
3636         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3637         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3638         MonoInst *ins;
3639         int dreg, addr_reg;
3640
3641         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3642
3643         /* obj */
3644         args [0] = obj;
3645
3646         /* klass */
3647         args [1] = klass_inst;
3648
3649         /* CASTCLASS */
3650         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3651
3652         NEW_BBLOCK (cfg, is_ref_bb);
3653         NEW_BBLOCK (cfg, is_nullable_bb);
3654         NEW_BBLOCK (cfg, end_bb);
3655         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3656         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3657         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3658
3659         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3660         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3661
3662         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3663         addr_reg = alloc_dreg (cfg, STACK_MP);
3664
3665         /* Non-ref case */
3666         /* UNBOX */
3667         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3668         MONO_ADD_INS (cfg->cbb, addr);
3669
3670         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3671
3672         /* Ref case */
3673         MONO_START_BB (cfg, is_ref_bb);
3674
3675         /* Save the ref to a temporary */
3676         dreg = alloc_ireg (cfg);
3677         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3678         addr->dreg = addr_reg;
3679         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3680         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3681
3682         /* Nullable case */
3683         MONO_START_BB (cfg, is_nullable_bb);
3684
3685         {
3686                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3687                 MonoInst *unbox_call;
3688                 MonoMethodSignature *unbox_sig;
3689                 MonoInst *var;
3690
3691                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3692
3693                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3694                 unbox_sig->ret = &klass->byval_arg;
3695                 unbox_sig->param_count = 1;
3696                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3697                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3698
3699                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3700                 addr->dreg = addr_reg;
3701         }
3702
3703         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3704
3705         /* End */
3706         MONO_START_BB (cfg, end_bb);
3707
3708         /* LDOBJ */
3709         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3710
3711         *out_cbb = cfg->cbb;
3712
3713         return ins;
3714 }
3715
3716 /*
3717  * Returns NULL and set the cfg exception on error.
3718  */
3719 static MonoInst*
3720 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3721 {
3722         MonoInst *iargs [2];
3723         void *alloc_ftn;
3724
3725         if (context_used) {
3726                 MonoInst *data;
3727                 int rgctx_info;
3728                 MonoInst *iargs [2];
3729
3730                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3731
3732                 if (cfg->opt & MONO_OPT_SHARED)
3733                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3734                 else
3735                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3736                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3737
3738                 if (cfg->opt & MONO_OPT_SHARED) {
3739                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3740                         iargs [1] = data;
3741                         alloc_ftn = mono_object_new;
3742                 } else {
3743                         iargs [0] = data;
3744                         alloc_ftn = mono_object_new_specific;
3745                 }
3746
3747                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3748                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3749
3750                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3751         }
3752
3753         if (cfg->opt & MONO_OPT_SHARED) {
3754                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3755                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3756
3757                 alloc_ftn = mono_object_new;
3758         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3759                 /* This happens often in argument checking code, eg. throw new FooException... */
3760                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3761                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3762                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3763         } else {
3764                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3765                 MonoMethod *managed_alloc = NULL;
3766                 gboolean pass_lw;
3767
3768                 if (!vtable) {
3769                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3770                         cfg->exception_ptr = klass;
3771                         return NULL;
3772                 }
3773
3774 #ifndef MONO_CROSS_COMPILE
3775                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3776 #endif
3777
3778                 if (managed_alloc) {
3779                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3780                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3781                 }
3782                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3783                 if (pass_lw) {
3784                         guint32 lw = vtable->klass->instance_size;
3785                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3786                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3787                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3788                 }
3789                 else {
3790                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3791                 }
3792         }
3793
3794         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3795 }
3796         
3797 /*
3798  * Returns NULL and set the cfg exception on error.
3799  */     
3800 static MonoInst*
3801 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3802 {
3803         MonoInst *alloc, *ins;
3804
3805         *out_cbb = cfg->cbb;
3806
3807         if (mono_class_is_nullable (klass)) {
3808                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3809
3810                 if (context_used) {
3811                         /* FIXME: What if the class is shared?  We might not
3812                            have to get the method address from the RGCTX. */
3813                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3814                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3815                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3816
3817                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3818                 } else {
3819                         gboolean pass_vtable, pass_mrgctx;
3820                         MonoInst *rgctx_arg = NULL;
3821
3822                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3823                         g_assert (!pass_mrgctx);
3824
3825                         if (pass_vtable) {
3826                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3827
3828                                 g_assert (vtable);
3829                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3830                         }
3831
3832                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3833                 }
3834         }
3835
3836         if (mini_is_gsharedvt_klass (cfg, klass)) {
3837                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3838                 MonoInst *res, *is_ref, *src_var, *addr;
3839                 int addr_reg, dreg;
3840
3841                 dreg = alloc_ireg (cfg);
3842
3843                 NEW_BBLOCK (cfg, is_ref_bb);
3844                 NEW_BBLOCK (cfg, is_nullable_bb);
3845                 NEW_BBLOCK (cfg, end_bb);
3846                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3847                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3848                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3849
3850                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3851                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3852
3853                 /* Non-ref case */
3854                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3855                 if (!alloc)
3856                         return NULL;
3857                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3858                 ins->opcode = OP_STOREV_MEMBASE;
3859
3860                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3861                 res->type = STACK_OBJ;
3862                 res->klass = klass;
3863                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3864                 
3865                 /* Ref case */
3866                 MONO_START_BB (cfg, is_ref_bb);
3867                 addr_reg = alloc_ireg (cfg);
3868
3869                 /* val is a vtype, so has to load the value manually */
3870                 src_var = get_vreg_to_inst (cfg, val->dreg);
3871                 if (!src_var)
3872                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3873                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3874                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3875                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3876
3877                 /* Nullable case */
3878                 MONO_START_BB (cfg, is_nullable_bb);
3879
3880                 {
3881                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3882                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3883                         MonoInst *box_call;
3884                         MonoMethodSignature *box_sig;
3885
3886                         /*
3887                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3888                          * construct that method at JIT time, so have to do things by hand.
3889                          */
3890                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3891                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3892                         box_sig->param_count = 1;
3893                         box_sig->params [0] = &klass->byval_arg;
3894                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3895                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3896                         res->type = STACK_OBJ;
3897                         res->klass = klass;
3898                 }
3899
3900                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3901
3902                 MONO_START_BB (cfg, end_bb);
3903
3904                 *out_cbb = cfg->cbb;
3905
3906                 return res;
3907         } else {
3908                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3909                 if (!alloc)
3910                         return NULL;
3911
3912                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3913                 return alloc;
3914         }
3915 }
3916
3917
3918 static gboolean
3919 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3920 {
3921         int i;
3922         MonoGenericContainer *container;
3923         MonoGenericInst *ginst;
3924
3925         if (klass->generic_class) {
3926                 container = klass->generic_class->container_class->generic_container;
3927                 ginst = klass->generic_class->context.class_inst;
3928         } else if (klass->generic_container && context_used) {
3929                 container = klass->generic_container;
3930                 ginst = container->context.class_inst;
3931         } else {
3932                 return FALSE;
3933         }
3934
3935         for (i = 0; i < container->type_argc; ++i) {
3936                 MonoType *type;
3937                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
3938                         continue;
3939                 type = ginst->type_argv [i];
3940                 if (mini_type_is_reference (cfg, type))
3941                         return TRUE;
3942         }
3943         return FALSE;
3944 }
3945
3946 // FIXME: This doesn't work yet (class libs tests fail?)
3947 #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)
3948
3949 /*
3950  * Returns NULL and set the cfg exception on error.
3951  */
3952 static MonoInst*
3953 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3954 {
3955         MonoBasicBlock *is_null_bb;
3956         int obj_reg = src->dreg;
3957         int vtable_reg = alloc_preg (cfg);
3958         MonoInst *klass_inst = NULL;
3959
3960         if (context_used) {
3961                 MonoInst *args [3];
3962
3963                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
3964                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
3965                         MonoInst *cache_ins;
3966
3967                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3968
3969                         /* obj */
3970                         args [0] = src;
3971
3972                         /* klass - it's the second element of the cache entry*/
3973                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3974
3975                         /* cache */
3976                         args [2] = cache_ins;
3977
3978                         return mono_emit_method_call (cfg, mono_castclass, args, NULL);
3979                 }
3980
3981                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3982         }
3983
3984         NEW_BBLOCK (cfg, is_null_bb);
3985
3986         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3987         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3988
3989         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
3990
3991         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3992                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3993                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
3994         } else {
3995                 int klass_reg = alloc_preg (cfg);
3996
3997                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3998
3999                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4000                         /* the remoting code is broken, access the class for now */
4001                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4002                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4003                                 if (!vt) {
4004                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4005                                         cfg->exception_ptr = klass;
4006                                         return NULL;
4007                                 }
4008                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4009                         } else {
4010                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4011                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4012                         }
4013                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4014                 } else {
4015                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4016                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4017                 }
4018         }
4019
4020         MONO_START_BB (cfg, is_null_bb);
4021
4022         reset_cast_details (cfg);
4023
4024         return src;
4025 }
4026
4027 /*
4028  * Returns NULL and set the cfg exception on error.
4029  */
4030 static MonoInst*
4031 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4032 {
4033         MonoInst *ins;
4034         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4035         int obj_reg = src->dreg;
4036         int vtable_reg = alloc_preg (cfg);
4037         int res_reg = alloc_ireg_ref (cfg);
4038         MonoInst *klass_inst = NULL;
4039
4040         if (context_used) {
4041                 MonoInst *args [3];
4042
4043                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4044                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4045                         MonoInst *cache_ins;
4046
4047                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4048
4049                         /* obj */
4050                         args [0] = src;
4051
4052                         /* klass - it's the second element of the cache entry*/
4053                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4054
4055                         /* cache */
4056                         args [2] = cache_ins;
4057
4058                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4059                 }
4060
4061                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4062         }
4063
4064         NEW_BBLOCK (cfg, is_null_bb);
4065         NEW_BBLOCK (cfg, false_bb);
4066         NEW_BBLOCK (cfg, end_bb);
4067
4068         /* Do the assignment at the beginning, so the other assignment can be if converted */
4069         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4070         ins->type = STACK_OBJ;
4071         ins->klass = klass;
4072
4073         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4074         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4075
4076         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4077
4078         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4079                 g_assert (!context_used);
4080                 /* the is_null_bb target simply copies the input register to the output */
4081                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4082         } else {
4083                 int klass_reg = alloc_preg (cfg);
4084
4085                 if (klass->rank) {
4086                         int rank_reg = alloc_preg (cfg);
4087                         int eclass_reg = alloc_preg (cfg);
4088
4089                         g_assert (!context_used);
4090                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4091                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4092                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4093                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4094                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4095                         if (klass->cast_class == mono_defaults.object_class) {
4096                                 int parent_reg = alloc_preg (cfg);
4097                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4098                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4099                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4100                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4101                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4102                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4103                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4104                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4105                         } else if (klass->cast_class == mono_defaults.enum_class) {
4106                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4107                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4108                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4109                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4110                         } else {
4111                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4112                                         /* Check that the object is a vector too */
4113                                         int bounds_reg = alloc_preg (cfg);
4114                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4115                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4116                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4117                                 }
4118
4119                                 /* the is_null_bb target simply copies the input register to the output */
4120                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4121                         }
4122                 } else if (mono_class_is_nullable (klass)) {
4123                         g_assert (!context_used);
4124                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4125                         /* the is_null_bb target simply copies the input register to the output */
4126                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4127                 } else {
4128                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4129                                 g_assert (!context_used);
4130                                 /* the remoting code is broken, access the class for now */
4131                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4132                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4133                                         if (!vt) {
4134                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4135                                                 cfg->exception_ptr = klass;
4136                                                 return NULL;
4137                                         }
4138                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4139                                 } else {
4140                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4141                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4142                                 }
4143                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4144                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4145                         } else {
4146                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4147                                 /* the is_null_bb target simply copies the input register to the output */
4148                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4149                         }
4150                 }
4151         }
4152
4153         MONO_START_BB (cfg, false_bb);
4154
4155         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4156         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4157
4158         MONO_START_BB (cfg, is_null_bb);
4159
4160         MONO_START_BB (cfg, end_bb);
4161
4162         return ins;
4163 }
4164
4165 static MonoInst*
4166 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4167 {
4168         /* This opcode takes as input an object reference and a class, and returns:
4169         0) if the object is an instance of the class,
4170         1) if the object is not instance of the class,
4171         2) if the object is a proxy whose type cannot be determined */
4172
4173         MonoInst *ins;
4174 #ifndef DISABLE_REMOTING
4175         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4176 #else
4177         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4178 #endif
4179         int obj_reg = src->dreg;
4180         int dreg = alloc_ireg (cfg);
4181         int tmp_reg;
4182 #ifndef DISABLE_REMOTING
4183         int klass_reg = alloc_preg (cfg);
4184 #endif
4185
4186         NEW_BBLOCK (cfg, true_bb);
4187         NEW_BBLOCK (cfg, false_bb);
4188         NEW_BBLOCK (cfg, end_bb);
4189 #ifndef DISABLE_REMOTING
4190         NEW_BBLOCK (cfg, false2_bb);
4191         NEW_BBLOCK (cfg, no_proxy_bb);
4192 #endif
4193
4194         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4195         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4196
4197         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4198 #ifndef DISABLE_REMOTING
4199                 NEW_BBLOCK (cfg, interface_fail_bb);
4200 #endif
4201
4202                 tmp_reg = alloc_preg (cfg);
4203                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4204 #ifndef DISABLE_REMOTING
4205                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4206                 MONO_START_BB (cfg, interface_fail_bb);
4207                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4208                 
4209                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4210
4211                 tmp_reg = alloc_preg (cfg);
4212                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4213                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4214                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4215 #else
4216                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4217 #endif
4218         } else {
4219 #ifndef DISABLE_REMOTING
4220                 tmp_reg = alloc_preg (cfg);
4221                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4222                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4223
4224                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4225                 tmp_reg = alloc_preg (cfg);
4226                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4227                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4228
4229                 tmp_reg = alloc_preg (cfg);             
4230                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4231                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4232                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4233                 
4234                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4235                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4236
4237                 MONO_START_BB (cfg, no_proxy_bb);
4238
4239                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4240 #else
4241                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4242 #endif
4243         }
4244
4245         MONO_START_BB (cfg, false_bb);
4246
4247         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4248         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4249
4250 #ifndef DISABLE_REMOTING
4251         MONO_START_BB (cfg, false2_bb);
4252
4253         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4254         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4255 #endif
4256
4257         MONO_START_BB (cfg, true_bb);
4258
4259         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4260
4261         MONO_START_BB (cfg, end_bb);
4262
4263         /* FIXME: */
4264         MONO_INST_NEW (cfg, ins, OP_ICONST);
4265         ins->dreg = dreg;
4266         ins->type = STACK_I4;
4267
4268         return ins;
4269 }
4270
4271 static MonoInst*
4272 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4273 {
4274         /* This opcode takes as input an object reference and a class, and returns:
4275         0) if the object is an instance of the class,
4276         1) if the object is a proxy whose type cannot be determined
4277         an InvalidCastException exception is thrown otherwhise*/
4278         
4279         MonoInst *ins;
4280 #ifndef DISABLE_REMOTING
4281         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4282 #else
4283         MonoBasicBlock *ok_result_bb;
4284 #endif
4285         int obj_reg = src->dreg;
4286         int dreg = alloc_ireg (cfg);
4287         int tmp_reg = alloc_preg (cfg);
4288
4289 #ifndef DISABLE_REMOTING
4290         int klass_reg = alloc_preg (cfg);
4291         NEW_BBLOCK (cfg, end_bb);
4292 #endif
4293
4294         NEW_BBLOCK (cfg, ok_result_bb);
4295
4296         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4297         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4298
4299         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4300
4301         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4302 #ifndef DISABLE_REMOTING
4303                 NEW_BBLOCK (cfg, interface_fail_bb);
4304         
4305                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4306                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4307                 MONO_START_BB (cfg, interface_fail_bb);
4308                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4309
4310                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4311
4312                 tmp_reg = alloc_preg (cfg);             
4313                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4314                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4315                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4316                 
4317                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4318                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4319 #else
4320                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4321                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4322                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4323 #endif
4324         } else {
4325 #ifndef DISABLE_REMOTING
4326                 NEW_BBLOCK (cfg, no_proxy_bb);
4327
4328                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4329                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4330                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4331
4332                 tmp_reg = alloc_preg (cfg);
4333                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4334                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4335
4336                 tmp_reg = alloc_preg (cfg);
4337                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4338                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4339                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4340
4341                 NEW_BBLOCK (cfg, fail_1_bb);
4342                 
4343                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4344
4345                 MONO_START_BB (cfg, fail_1_bb);
4346
4347                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4348                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4349
4350                 MONO_START_BB (cfg, no_proxy_bb);
4351
4352                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4353 #else
4354                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4355 #endif
4356         }
4357
4358         MONO_START_BB (cfg, ok_result_bb);
4359
4360         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4361
4362 #ifndef DISABLE_REMOTING
4363         MONO_START_BB (cfg, end_bb);
4364 #endif
4365
4366         /* FIXME: */
4367         MONO_INST_NEW (cfg, ins, OP_ICONST);
4368         ins->dreg = dreg;
4369         ins->type = STACK_I4;
4370
4371         return ins;
4372 }
4373
4374 /*
4375  * Returns NULL and set the cfg exception on error.
4376  */
4377 static G_GNUC_UNUSED MonoInst*
4378 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4379 {
4380         MonoInst *ptr;
4381         int dreg;
4382         gpointer *trampoline;
4383         MonoInst *obj, *method_ins, *tramp_ins;
4384         MonoDomain *domain;
4385         guint8 **code_slot;
4386
4387         obj = handle_alloc (cfg, klass, FALSE, 0);
4388         if (!obj)
4389                 return NULL;
4390
4391         /* Inline the contents of mono_delegate_ctor */
4392
4393         /* Set target field */
4394         /* Optimize away setting of NULL target */
4395         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4396                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4397                 if (cfg->gen_write_barriers) {
4398                         dreg = alloc_preg (cfg);
4399                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4400                         emit_write_barrier (cfg, ptr, target);
4401                 }
4402         }
4403
4404         /* Set method field */
4405         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4406         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4407         if (cfg->gen_write_barriers) {
4408                 dreg = alloc_preg (cfg);
4409                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4410                 emit_write_barrier (cfg, ptr, method_ins);
4411         }
4412         /* 
4413          * To avoid looking up the compiled code belonging to the target method
4414          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4415          * store it, and we fill it after the method has been compiled.
4416          */
4417         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4418                 MonoInst *code_slot_ins;
4419
4420                 if (context_used) {
4421                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4422                 } else {
4423                         domain = mono_domain_get ();
4424                         mono_domain_lock (domain);
4425                         if (!domain_jit_info (domain)->method_code_hash)
4426                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4427                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4428                         if (!code_slot) {
4429                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4430                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4431                         }
4432                         mono_domain_unlock (domain);
4433
4434                         if (cfg->compile_aot)
4435                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4436                         else
4437                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4438                 }
4439                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4440         }
4441
4442         /* Set invoke_impl field */
4443         if (cfg->compile_aot) {
4444                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
4445         } else {
4446                 trampoline = mono_create_delegate_trampoline (cfg->domain, klass);
4447                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4448         }
4449         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4450
4451         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4452
4453         return obj;
4454 }
4455
4456 static MonoInst*
4457 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4458 {
4459         MonoJitICallInfo *info;
4460
4461         /* Need to register the icall so it gets an icall wrapper */
4462         info = mono_get_array_new_va_icall (rank);
4463
4464         cfg->flags |= MONO_CFG_HAS_VARARGS;
4465
4466         /* mono_array_new_va () needs a vararg calling convention */
4467         cfg->disable_llvm = TRUE;
4468
4469         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4470         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4471 }
4472
4473 static void
4474 mono_emit_load_got_addr (MonoCompile *cfg)
4475 {
4476         MonoInst *getaddr, *dummy_use;
4477
4478         if (!cfg->got_var || cfg->got_var_allocated)
4479                 return;
4480
4481         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4482         getaddr->cil_code = cfg->header->code;
4483         getaddr->dreg = cfg->got_var->dreg;
4484
4485         /* Add it to the start of the first bblock */
4486         if (cfg->bb_entry->code) {
4487                 getaddr->next = cfg->bb_entry->code;
4488                 cfg->bb_entry->code = getaddr;
4489         }
4490         else
4491                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4492
4493         cfg->got_var_allocated = TRUE;
4494
4495         /* 
4496          * Add a dummy use to keep the got_var alive, since real uses might
4497          * only be generated by the back ends.
4498          * Add it to end_bblock, so the variable's lifetime covers the whole
4499          * method.
4500          * It would be better to make the usage of the got var explicit in all
4501          * cases when the backend needs it (i.e. calls, throw etc.), so this
4502          * wouldn't be needed.
4503          */
4504         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4505         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4506 }
4507
4508 static int inline_limit;
4509 static gboolean inline_limit_inited;
4510
4511 static gboolean
4512 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4513 {
4514         MonoMethodHeaderSummary header;
4515         MonoVTable *vtable;
4516 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4517         MonoMethodSignature *sig = mono_method_signature (method);
4518         int i;
4519 #endif
4520
4521         if (cfg->generic_sharing_context)
4522                 return FALSE;
4523
4524         if (cfg->inline_depth > 10)
4525                 return FALSE;
4526
4527 #ifdef MONO_ARCH_HAVE_LMF_OPS
4528         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4529                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4530             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4531                 return TRUE;
4532 #endif
4533
4534
4535         if (!mono_method_get_header_summary (method, &header))
4536                 return FALSE;
4537
4538         /*runtime, icall and pinvoke are checked by summary call*/
4539         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4540             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4541             (mono_class_is_marshalbyref (method->klass)) ||
4542             header.has_clauses)
4543                 return FALSE;
4544
4545         /* also consider num_locals? */
4546         /* Do the size check early to avoid creating vtables */
4547         if (!inline_limit_inited) {
4548                 if (g_getenv ("MONO_INLINELIMIT"))
4549                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4550                 else
4551                         inline_limit = INLINE_LENGTH_LIMIT;
4552                 inline_limit_inited = TRUE;
4553         }
4554         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4555                 return FALSE;
4556
4557         /*
4558          * if we can initialize the class of the method right away, we do,
4559          * otherwise we don't allow inlining if the class needs initialization,
4560          * since it would mean inserting a call to mono_runtime_class_init()
4561          * inside the inlined code
4562          */
4563         if (!(cfg->opt & MONO_OPT_SHARED)) {
4564                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4565                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4566                         vtable = mono_class_vtable (cfg->domain, method->klass);
4567                         if (!vtable)
4568                                 return FALSE;
4569                         mono_runtime_class_init (vtable);
4570                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4571                         if (cfg->run_cctors && method->klass->has_cctor) {
4572                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4573                                 if (!method->klass->runtime_info)
4574                                         /* No vtable created yet */
4575                                         return FALSE;
4576                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4577                                 if (!vtable)
4578                                         return FALSE;
4579                                 /* This makes so that inline cannot trigger */
4580                                 /* .cctors: too many apps depend on them */
4581                                 /* running with a specific order... */
4582                                 if (! vtable->initialized)
4583                                         return FALSE;
4584                                 mono_runtime_class_init (vtable);
4585                         }
4586                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4587                         if (!method->klass->runtime_info)
4588                                 /* No vtable created yet */
4589                                 return FALSE;
4590                         vtable = mono_class_vtable (cfg->domain, method->klass);
4591                         if (!vtable)
4592                                 return FALSE;
4593                         if (!vtable->initialized)
4594                                 return FALSE;
4595                 }
4596         } else {
4597                 /* 
4598                  * If we're compiling for shared code
4599                  * the cctor will need to be run at aot method load time, for example,
4600                  * or at the end of the compilation of the inlining method.
4601                  */
4602                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4603                         return FALSE;
4604         }
4605
4606         /*
4607          * CAS - do not inline methods with declarative security
4608          * Note: this has to be before any possible return TRUE;
4609          */
4610         if (mono_security_method_has_declsec (method))
4611                 return FALSE;
4612
4613 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4614         if (mono_arch_is_soft_float ()) {
4615                 /* FIXME: */
4616                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4617                         return FALSE;
4618                 for (i = 0; i < sig->param_count; ++i)
4619                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4620                                 return FALSE;
4621         }
4622 #endif
4623
4624         return TRUE;
4625 }
4626
4627 static gboolean
4628 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4629 {
4630         if (!cfg->compile_aot) {
4631                 g_assert (vtable);
4632                 if (vtable->initialized)
4633                         return FALSE;
4634         }
4635
4636         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
4637                 return FALSE;
4638
4639         if (!mono_class_needs_cctor_run (klass, method))
4640                 return FALSE;
4641
4642         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4643                 /* The initialization is already done before the method is called */
4644                 return FALSE;
4645
4646         return TRUE;
4647 }
4648
4649 static MonoInst*
4650 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4651 {
4652         MonoInst *ins;
4653         guint32 size;
4654         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4655         int context_used;
4656
4657         if (mini_is_gsharedvt_klass (cfg, klass)) {
4658                 size = -1;
4659         } else {
4660                 mono_class_init (klass);
4661                 size = mono_class_array_element_size (klass);
4662         }
4663
4664         mult_reg = alloc_preg (cfg);
4665         array_reg = arr->dreg;
4666         index_reg = index->dreg;
4667
4668 #if SIZEOF_REGISTER == 8
4669         /* The array reg is 64 bits but the index reg is only 32 */
4670         if (COMPILE_LLVM (cfg)) {
4671                 /* Not needed */
4672                 index2_reg = index_reg;
4673         } else {
4674                 index2_reg = alloc_preg (cfg);
4675                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4676         }
4677 #else
4678         if (index->type == STACK_I8) {
4679                 index2_reg = alloc_preg (cfg);
4680                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4681         } else {
4682                 index2_reg = index_reg;
4683         }
4684 #endif
4685
4686         if (bcheck)
4687                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4688
4689 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4690         if (size == 1 || size == 2 || size == 4 || size == 8) {
4691                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4692
4693                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4694                 ins->klass = mono_class_get_element_class (klass);
4695                 ins->type = STACK_MP;
4696
4697                 return ins;
4698         }
4699 #endif          
4700
4701         add_reg = alloc_ireg_mp (cfg);
4702
4703         if (size == -1) {
4704                 MonoInst *rgctx_ins;
4705
4706                 /* gsharedvt */
4707                 g_assert (cfg->generic_sharing_context);
4708                 context_used = mini_class_check_context_used (cfg, klass);
4709                 g_assert (context_used);
4710                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4711                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4712         } else {
4713                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4714         }
4715         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4716         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4717         ins->klass = mono_class_get_element_class (klass);
4718         ins->type = STACK_MP;
4719         MONO_ADD_INS (cfg->cbb, ins);
4720
4721         return ins;
4722 }
4723
4724 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4725 static MonoInst*
4726 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4727 {
4728         int bounds_reg = alloc_preg (cfg);
4729         int add_reg = alloc_ireg_mp (cfg);
4730         int mult_reg = alloc_preg (cfg);
4731         int mult2_reg = alloc_preg (cfg);
4732         int low1_reg = alloc_preg (cfg);
4733         int low2_reg = alloc_preg (cfg);
4734         int high1_reg = alloc_preg (cfg);
4735         int high2_reg = alloc_preg (cfg);
4736         int realidx1_reg = alloc_preg (cfg);
4737         int realidx2_reg = alloc_preg (cfg);
4738         int sum_reg = alloc_preg (cfg);
4739         int index1, index2, tmpreg;
4740         MonoInst *ins;
4741         guint32 size;
4742
4743         mono_class_init (klass);
4744         size = mono_class_array_element_size (klass);
4745
4746         index1 = index_ins1->dreg;
4747         index2 = index_ins2->dreg;
4748
4749 #if SIZEOF_REGISTER == 8
4750         /* The array reg is 64 bits but the index reg is only 32 */
4751         if (COMPILE_LLVM (cfg)) {
4752                 /* Not needed */
4753         } else {
4754                 tmpreg = alloc_preg (cfg);
4755                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4756                 index1 = tmpreg;
4757                 tmpreg = alloc_preg (cfg);
4758                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4759                 index2 = tmpreg;
4760         }
4761 #else
4762         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4763         tmpreg = -1;
4764 #endif
4765
4766         /* range checking */
4767         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4768                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4769
4770         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4771                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4772         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4773         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4774                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4775         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4776         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4777
4778         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4779                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4780         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4781         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4782                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4783         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4784         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4785
4786         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4787         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4788         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4789         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4790         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4791
4792         ins->type = STACK_MP;
4793         ins->klass = klass;
4794         MONO_ADD_INS (cfg->cbb, ins);
4795
4796         return ins;
4797 }
4798 #endif
4799
4800 static MonoInst*
4801 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4802 {
4803         int rank;
4804         MonoInst *addr;
4805         MonoMethod *addr_method;
4806         int element_size;
4807
4808         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4809
4810         if (rank == 1)
4811                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4812
4813 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4814         /* emit_ldelema_2 depends on OP_LMUL */
4815         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4816                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4817         }
4818 #endif
4819
4820         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4821         addr_method = mono_marshal_get_array_address (rank, element_size);
4822         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4823
4824         return addr;
4825 }
4826
4827 static MonoBreakPolicy
4828 always_insert_breakpoint (MonoMethod *method)
4829 {
4830         return MONO_BREAK_POLICY_ALWAYS;
4831 }
4832
4833 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4834
4835 /**
4836  * mono_set_break_policy:
4837  * policy_callback: the new callback function
4838  *
4839  * Allow embedders to decide wherther to actually obey breakpoint instructions
4840  * (both break IL instructions and Debugger.Break () method calls), for example
4841  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4842  * untrusted or semi-trusted code.
4843  *
4844  * @policy_callback will be called every time a break point instruction needs to
4845  * be inserted with the method argument being the method that calls Debugger.Break()
4846  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4847  * if it wants the breakpoint to not be effective in the given method.
4848  * #MONO_BREAK_POLICY_ALWAYS is the default.
4849  */
4850 void
4851 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4852 {
4853         if (policy_callback)
4854                 break_policy_func = policy_callback;
4855         else
4856                 break_policy_func = always_insert_breakpoint;
4857 }
4858
4859 static gboolean
4860 should_insert_brekpoint (MonoMethod *method) {
4861         switch (break_policy_func (method)) {
4862         case MONO_BREAK_POLICY_ALWAYS:
4863                 return TRUE;
4864         case MONO_BREAK_POLICY_NEVER:
4865                 return FALSE;
4866         case MONO_BREAK_POLICY_ON_DBG:
4867                 g_warning ("mdb no longer supported");
4868                 return FALSE;
4869         default:
4870                 g_warning ("Incorrect value returned from break policy callback");
4871                 return FALSE;
4872         }
4873 }
4874
4875 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4876 static MonoInst*
4877 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4878 {
4879         MonoInst *addr, *store, *load;
4880         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4881
4882         /* the bounds check is already done by the callers */
4883         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4884         if (is_set) {
4885                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4886                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4887                 if (mini_type_is_reference (cfg, fsig->params [2]))
4888                         emit_write_barrier (cfg, addr, load);
4889         } else {
4890                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4891                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4892         }
4893         return store;
4894 }
4895
4896
4897 static gboolean
4898 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4899 {
4900         return mini_type_is_reference (cfg, &klass->byval_arg);
4901 }
4902
4903 static MonoInst*
4904 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4905 {
4906         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4907                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
4908                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4909                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4910                 MonoInst *iargs [3];
4911
4912                 if (!helper->slot)
4913                         mono_class_setup_vtable (obj_array);
4914                 g_assert (helper->slot);
4915
4916                 if (sp [0]->type != STACK_OBJ)
4917                         return NULL;
4918                 if (sp [2]->type != STACK_OBJ)
4919                         return NULL;
4920
4921                 iargs [2] = sp [2];
4922                 iargs [1] = sp [1];
4923                 iargs [0] = sp [0];
4924
4925                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4926         } else {
4927                 MonoInst *ins;
4928
4929                 if (mini_is_gsharedvt_klass (cfg, klass)) {
4930                         MonoInst *addr;
4931
4932                         // FIXME-VT: OP_ICONST optimization
4933                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4934                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4935                         ins->opcode = OP_STOREV_MEMBASE;
4936                 } else if (sp [1]->opcode == OP_ICONST) {
4937                         int array_reg = sp [0]->dreg;
4938                         int index_reg = sp [1]->dreg;
4939                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
4940
4941                         if (safety_checks)
4942                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4943                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4944                 } else {
4945                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4946                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4947                         if (generic_class_is_reference_type (cfg, klass))
4948                                 emit_write_barrier (cfg, addr, sp [2]);
4949                 }
4950                 return ins;
4951         }
4952 }
4953
4954 static MonoInst*
4955 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4956 {
4957         MonoClass *eklass;
4958         
4959         if (is_set)
4960                 eklass = mono_class_from_mono_type (fsig->params [2]);
4961         else
4962                 eklass = mono_class_from_mono_type (fsig->ret);
4963
4964
4965         if (is_set) {
4966                 return emit_array_store (cfg, eklass, args, FALSE);
4967         } else {
4968                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4969                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4970                 return ins;
4971         }
4972 }
4973
4974 static MonoInst*
4975 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4976 {
4977         MonoInst *ins = NULL;
4978 #ifdef MONO_ARCH_SIMD_INTRINSICS
4979         if (cfg->opt & MONO_OPT_SIMD) {
4980                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4981                 if (ins)
4982                         return ins;
4983         }
4984 #endif
4985
4986         return ins;
4987 }
4988
4989 static MonoInst*
4990 emit_memory_barrier (MonoCompile *cfg, int kind)
4991 {
4992         MonoInst *ins = NULL;
4993         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4994         MONO_ADD_INS (cfg->cbb, ins);
4995         ins->backend.memory_barrier_kind = kind;
4996
4997         return ins;
4998 }
4999
5000 static MonoInst*
5001 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5002 {
5003         MonoInst *ins = NULL;
5004         int opcode = 0;
5005
5006         /* The LLVM backend supports these intrinsics */
5007         if (cmethod->klass == mono_defaults.math_class) {
5008                 if (strcmp (cmethod->name, "Sin") == 0) {
5009                         opcode = OP_SIN;
5010                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5011                         opcode = OP_COS;
5012                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5013                         opcode = OP_SQRT;
5014                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5015                         opcode = OP_ABS;
5016                 }
5017
5018                 if (opcode) {
5019                         MONO_INST_NEW (cfg, ins, opcode);
5020                         ins->type = STACK_R8;
5021                         ins->dreg = mono_alloc_freg (cfg);
5022                         ins->sreg1 = args [0]->dreg;
5023                         MONO_ADD_INS (cfg->cbb, ins);
5024                 }
5025
5026                 opcode = 0;
5027                 if (cfg->opt & MONO_OPT_CMOV) {
5028                         if (strcmp (cmethod->name, "Min") == 0) {
5029                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5030                                         opcode = OP_IMIN;
5031                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5032                                         opcode = OP_IMIN_UN;
5033                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5034                                         opcode = OP_LMIN;
5035                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5036                                         opcode = OP_LMIN_UN;
5037                         } else if (strcmp (cmethod->name, "Max") == 0) {
5038                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5039                                         opcode = OP_IMAX;
5040                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5041                                         opcode = OP_IMAX_UN;
5042                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5043                                         opcode = OP_LMAX;
5044                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5045                                         opcode = OP_LMAX_UN;
5046                         }
5047                 }
5048
5049                 if (opcode) {
5050                         MONO_INST_NEW (cfg, ins, opcode);
5051                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5052                         ins->dreg = mono_alloc_ireg (cfg);
5053                         ins->sreg1 = args [0]->dreg;
5054                         ins->sreg2 = args [1]->dreg;
5055                         MONO_ADD_INS (cfg->cbb, ins);
5056                 }
5057         }
5058
5059         return ins;
5060 }
5061
5062 static MonoInst*
5063 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5064 {
5065         if (cmethod->klass == mono_defaults.array_class) {
5066                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5067                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5068                 if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5069                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5070         }
5071
5072         return NULL;
5073 }
5074
5075 static MonoInst*
5076 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5077 {
5078         MonoInst *ins = NULL;
5079         
5080         static MonoClass *runtime_helpers_class = NULL;
5081         if (! runtime_helpers_class)
5082                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5083                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5084
5085         if (cmethod->klass == mono_defaults.string_class) {
5086                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5087                         int dreg = alloc_ireg (cfg);
5088                         int index_reg = alloc_preg (cfg);
5089                         int mult_reg = alloc_preg (cfg);
5090                         int add_reg = alloc_preg (cfg);
5091
5092 #if SIZEOF_REGISTER == 8
5093                         /* The array reg is 64 bits but the index reg is only 32 */
5094                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5095 #else
5096                         index_reg = args [1]->dreg;
5097 #endif  
5098                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5099
5100 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5101                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5102                         add_reg = ins->dreg;
5103                         /* Avoid a warning */
5104                         mult_reg = 0;
5105                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5106                                                                    add_reg, 0);
5107 #else
5108                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5109                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5110                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5111                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5112 #endif
5113                         type_from_op (ins, NULL, NULL);
5114                         return ins;
5115                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5116                         int dreg = alloc_ireg (cfg);
5117                         /* Decompose later to allow more optimizations */
5118                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5119                         ins->type = STACK_I4;
5120                         ins->flags |= MONO_INST_FAULT;
5121                         cfg->cbb->has_array_access = TRUE;
5122                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5123
5124                         return ins;
5125                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5126                         int mult_reg = alloc_preg (cfg);
5127                         int add_reg = alloc_preg (cfg);
5128
5129                         /* The corlib functions check for oob already. */
5130                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5131                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5132                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5133                         return cfg->cbb->last_ins;
5134                 } else 
5135                         return NULL;
5136         } else if (cmethod->klass == mono_defaults.object_class) {
5137
5138                 if (strcmp (cmethod->name, "GetType") == 0) {
5139                         int dreg = alloc_ireg_ref (cfg);
5140                         int vt_reg = alloc_preg (cfg);
5141                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5142                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5143                         type_from_op (ins, NULL, NULL);
5144
5145                         return ins;
5146 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5147                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5148                         int dreg = alloc_ireg (cfg);
5149                         int t1 = alloc_ireg (cfg);
5150         
5151                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5152                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5153                         ins->type = STACK_I4;
5154
5155                         return ins;
5156 #endif
5157                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5158                         MONO_INST_NEW (cfg, ins, OP_NOP);
5159                         MONO_ADD_INS (cfg->cbb, ins);
5160                         return ins;
5161                 } else
5162                         return NULL;
5163         } else if (cmethod->klass == mono_defaults.array_class) {
5164                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5165                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5166
5167 #ifndef MONO_BIG_ARRAYS
5168                 /*
5169                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5170                  * Array methods.
5171                  */
5172                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5173                         int dreg = alloc_ireg (cfg);
5174                         int bounds_reg = alloc_ireg_mp (cfg);
5175                         MonoBasicBlock *end_bb, *szarray_bb;
5176                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5177
5178                         NEW_BBLOCK (cfg, end_bb);
5179                         NEW_BBLOCK (cfg, szarray_bb);
5180
5181                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5182                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5183                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5184                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5185                         /* Non-szarray case */
5186                         if (get_length)
5187                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5188                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5189                         else
5190                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5191                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5192                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5193                         MONO_START_BB (cfg, szarray_bb);
5194                         /* Szarray case */
5195                         if (get_length)
5196                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5197                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5198                         else
5199                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5200                         MONO_START_BB (cfg, end_bb);
5201
5202                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5203                         ins->type = STACK_I4;
5204                         
5205                         return ins;
5206                 }
5207 #endif
5208
5209                 if (cmethod->name [0] != 'g')
5210                         return NULL;
5211
5212                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5213                         int dreg = alloc_ireg (cfg);
5214                         int vtable_reg = alloc_preg (cfg);
5215                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5216                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5217                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5218                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5219                         type_from_op (ins, NULL, NULL);
5220
5221                         return ins;
5222                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5223                         int dreg = alloc_ireg (cfg);
5224
5225                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5226                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5227                         type_from_op (ins, NULL, NULL);
5228
5229                         return ins;
5230                 } else
5231                         return NULL;
5232         } else if (cmethod->klass == runtime_helpers_class) {
5233
5234                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5235                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5236                         return ins;
5237                 } else
5238                         return NULL;
5239         } else if (cmethod->klass == mono_defaults.thread_class) {
5240                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5241                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5242                         MONO_ADD_INS (cfg->cbb, ins);
5243                         return ins;
5244                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5245                         return emit_memory_barrier (cfg, FullBarrier);
5246                 }
5247         } else if (cmethod->klass == mono_defaults.monitor_class) {
5248
5249                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5250 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5251                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5252                         MonoMethod *fast_method = NULL;
5253
5254                         /* Avoid infinite recursion */
5255                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5256                                 return NULL;
5257                                 
5258                         fast_method = mono_monitor_get_fast_path (cmethod);
5259                         if (!fast_method)
5260                                 return NULL;
5261
5262                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5263                 }
5264 #endif
5265
5266 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5267                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5268                         MonoCallInst *call;
5269
5270                         if (COMPILE_LLVM (cfg)) {
5271                                 /* 
5272                                  * Pass the argument normally, the LLVM backend will handle the
5273                                  * calling convention problems.
5274                                  */
5275                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5276                         } else {
5277                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5278                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5279                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5280                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5281                         }
5282
5283                         return (MonoInst*)call;
5284                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5285                         MonoCallInst *call;
5286
5287                         if (COMPILE_LLVM (cfg)) {
5288                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5289                         } else {
5290                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5291                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5292                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5293                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5294                         }
5295
5296                         return (MonoInst*)call;
5297                 }
5298 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5299                 {
5300                 MonoMethod *fast_method = NULL;
5301
5302                 /* Avoid infinite recursion */
5303                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5304                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5305                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5306                         return NULL;
5307
5308                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5309                                 strcmp (cmethod->name, "Exit") == 0)
5310                         fast_method = mono_monitor_get_fast_path (cmethod);
5311                 if (!fast_method)
5312                         return NULL;
5313
5314                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5315                 }
5316 #endif
5317         } else if (cmethod->klass->image == mono_defaults.corlib &&
5318                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5319                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5320                 ins = NULL;
5321
5322 #if SIZEOF_REGISTER == 8
5323                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5324                         /* 64 bit reads are already atomic */
5325                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5326                         ins->dreg = mono_alloc_preg (cfg);
5327                         ins->inst_basereg = args [0]->dreg;
5328                         ins->inst_offset = 0;
5329                         MONO_ADD_INS (cfg->cbb, ins);
5330                 }
5331 #endif
5332
5333 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5334                 if (strcmp (cmethod->name, "Increment") == 0) {
5335                         MonoInst *ins_iconst;
5336                         guint32 opcode = 0;
5337
5338                         if (fsig->params [0]->type == MONO_TYPE_I4)
5339                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5340 #if SIZEOF_REGISTER == 8
5341                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5342                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5343 #endif
5344                         if (opcode) {
5345                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5346                                 ins_iconst->inst_c0 = 1;
5347                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5348                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5349
5350                                 MONO_INST_NEW (cfg, ins, opcode);
5351                                 ins->dreg = mono_alloc_ireg (cfg);
5352                                 ins->inst_basereg = args [0]->dreg;
5353                                 ins->inst_offset = 0;
5354                                 ins->sreg2 = ins_iconst->dreg;
5355                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5356                                 MONO_ADD_INS (cfg->cbb, ins);
5357                         }
5358                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5359                         MonoInst *ins_iconst;
5360                         guint32 opcode = 0;
5361
5362                         if (fsig->params [0]->type == MONO_TYPE_I4)
5363                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5364 #if SIZEOF_REGISTER == 8
5365                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5366                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5367 #endif
5368                         if (opcode) {
5369                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5370                                 ins_iconst->inst_c0 = -1;
5371                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5372                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5373
5374                                 MONO_INST_NEW (cfg, ins, opcode);
5375                                 ins->dreg = mono_alloc_ireg (cfg);
5376                                 ins->inst_basereg = args [0]->dreg;
5377                                 ins->inst_offset = 0;
5378                                 ins->sreg2 = ins_iconst->dreg;
5379                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5380                                 MONO_ADD_INS (cfg->cbb, ins);
5381                         }
5382                 } else if (strcmp (cmethod->name, "Add") == 0) {
5383                         guint32 opcode = 0;
5384
5385                         if (fsig->params [0]->type == MONO_TYPE_I4)
5386                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5387 #if SIZEOF_REGISTER == 8
5388                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5389                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5390 #endif
5391
5392                         if (opcode) {
5393                                 MONO_INST_NEW (cfg, ins, opcode);
5394                                 ins->dreg = mono_alloc_ireg (cfg);
5395                                 ins->inst_basereg = args [0]->dreg;
5396                                 ins->inst_offset = 0;
5397                                 ins->sreg2 = args [1]->dreg;
5398                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5399                                 MONO_ADD_INS (cfg->cbb, ins);
5400                         }
5401                 }
5402 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5403
5404 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5405                 if (strcmp (cmethod->name, "Exchange") == 0) {
5406                         guint32 opcode;
5407                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5408
5409                         if (fsig->params [0]->type == MONO_TYPE_I4)
5410                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5411 #if SIZEOF_REGISTER == 8
5412                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5413                                         (fsig->params [0]->type == MONO_TYPE_I))
5414                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5415 #else
5416                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
5417                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5418 #endif
5419                         else
5420                                 return NULL;
5421
5422                         MONO_INST_NEW (cfg, ins, opcode);
5423                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5424                         ins->inst_basereg = args [0]->dreg;
5425                         ins->inst_offset = 0;
5426                         ins->sreg2 = args [1]->dreg;
5427                         MONO_ADD_INS (cfg->cbb, ins);
5428
5429                         switch (fsig->params [0]->type) {
5430                         case MONO_TYPE_I4:
5431                                 ins->type = STACK_I4;
5432                                 break;
5433                         case MONO_TYPE_I8:
5434                         case MONO_TYPE_I:
5435                                 ins->type = STACK_I8;
5436                                 break;
5437                         case MONO_TYPE_OBJECT:
5438                                 ins->type = STACK_OBJ;
5439                                 break;
5440                         default:
5441                                 g_assert_not_reached ();
5442                         }
5443
5444                         if (cfg->gen_write_barriers && is_ref)
5445                                 emit_write_barrier (cfg, args [0], args [1]);
5446                 }
5447 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5448  
5449 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5450                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5451                         int size = 0;
5452                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5453                         if (fsig->params [1]->type == MONO_TYPE_I4)
5454                                 size = 4;
5455                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5456                                 size = sizeof (gpointer);
5457                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5458                                 size = 8;
5459                         if (size == 4) {
5460                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5461                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5462                                 ins->sreg1 = args [0]->dreg;
5463                                 ins->sreg2 = args [1]->dreg;
5464                                 ins->sreg3 = args [2]->dreg;
5465                                 ins->type = STACK_I4;
5466                                 MONO_ADD_INS (cfg->cbb, ins);
5467                         } else if (size == 8) {
5468                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5469                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5470                                 ins->sreg1 = args [0]->dreg;
5471                                 ins->sreg2 = args [1]->dreg;
5472                                 ins->sreg3 = args [2]->dreg;
5473                                 ins->type = STACK_I8;
5474                                 MONO_ADD_INS (cfg->cbb, ins);
5475                         } else {
5476                                 /* g_assert_not_reached (); */
5477                         }
5478                         if (cfg->gen_write_barriers && is_ref)
5479                                 emit_write_barrier (cfg, args [0], args [1]);
5480                 }
5481 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5482
5483                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5484                         ins = emit_memory_barrier (cfg, FullBarrier);
5485
5486                 if (ins)
5487                         return ins;
5488         } else if (cmethod->klass->image == mono_defaults.corlib) {
5489                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5490                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5491                         if (should_insert_brekpoint (cfg->method)) {
5492                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5493                         } else {
5494                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5495                                 MONO_ADD_INS (cfg->cbb, ins);
5496                         }
5497                         return ins;
5498                 }
5499                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5500                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5501 #ifdef TARGET_WIN32
5502                         EMIT_NEW_ICONST (cfg, ins, 1);
5503 #else
5504                         EMIT_NEW_ICONST (cfg, ins, 0);
5505 #endif
5506                         return ins;
5507                 }
5508         } else if (cmethod->klass == mono_defaults.math_class) {
5509                 /* 
5510                  * There is general branches code for Min/Max, but it does not work for 
5511                  * all inputs:
5512                  * http://everything2.com/?node_id=1051618
5513                  */
5514         } 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)) {
5515 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5516                 MonoInst *pi;
5517                 MonoJumpInfoToken *ji;
5518                 MonoString *s;
5519
5520                 cfg->disable_llvm = TRUE;
5521
5522                 if (args [0]->opcode == OP_GOT_ENTRY) {
5523                         pi = args [0]->inst_p1;
5524                         g_assert (pi->opcode == OP_PATCH_INFO);
5525                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5526                         ji = pi->inst_p0;
5527                 } else {
5528                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5529                         ji = args [0]->inst_p0;
5530                 }
5531
5532                 NULLIFY_INS (args [0]);
5533
5534                 // FIXME: Ugly
5535                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5536                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5537                 ins->dreg = mono_alloc_ireg (cfg);
5538                 // FIXME: Leaks
5539                 ins->inst_p0 = mono_string_to_utf8 (s);
5540                 MONO_ADD_INS (cfg->cbb, ins);
5541                 return ins;
5542 #endif
5543         }
5544
5545 #ifdef MONO_ARCH_SIMD_INTRINSICS
5546         if (cfg->opt & MONO_OPT_SIMD) {
5547                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5548                 if (ins)
5549                         return ins;
5550         }
5551 #endif
5552
5553         if (COMPILE_LLVM (cfg)) {
5554                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5555                 if (ins)
5556                         return ins;
5557         }
5558
5559         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5560 }
5561
5562 /*
5563  * This entry point could be used later for arbitrary method
5564  * redirection.
5565  */
5566 inline static MonoInst*
5567 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5568                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5569 {
5570         if (method->klass == mono_defaults.string_class) {
5571                 /* managed string allocation support */
5572                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5573                         MonoInst *iargs [2];
5574                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5575                         MonoMethod *managed_alloc = NULL;
5576
5577                         g_assert (vtable); /*Should not fail since it System.String*/
5578 #ifndef MONO_CROSS_COMPILE
5579                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5580 #endif
5581                         if (!managed_alloc)
5582                                 return NULL;
5583                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5584                         iargs [1] = args [0];
5585                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5586                 }
5587         }
5588         return NULL;
5589 }
5590
5591 static void
5592 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5593 {
5594         MonoInst *store, *temp;
5595         int i;
5596
5597         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5598                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5599
5600                 /*
5601                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5602                  * would be different than the MonoInst's used to represent arguments, and
5603                  * the ldelema implementation can't deal with that.
5604                  * Solution: When ldelema is used on an inline argument, create a var for 
5605                  * it, emit ldelema on that var, and emit the saving code below in
5606                  * inline_method () if needed.
5607                  */
5608                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5609                 cfg->args [i] = temp;
5610                 /* This uses cfg->args [i] which is set by the preceeding line */
5611                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5612                 store->cil_code = sp [0]->cil_code;
5613                 sp++;
5614         }
5615 }
5616
5617 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5618 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5619
5620 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5621 static gboolean
5622 check_inline_called_method_name_limit (MonoMethod *called_method)
5623 {
5624         int strncmp_result;
5625         static const char *limit = NULL;
5626         
5627         if (limit == NULL) {
5628                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5629
5630                 if (limit_string != NULL)
5631                         limit = limit_string;
5632                 else
5633                         limit = "";
5634         }
5635
5636         if (limit [0] != '\0') {
5637                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5638
5639                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5640                 g_free (called_method_name);
5641         
5642                 //return (strncmp_result <= 0);
5643                 return (strncmp_result == 0);
5644         } else {
5645                 return TRUE;
5646         }
5647 }
5648 #endif
5649
5650 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5651 static gboolean
5652 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5653 {
5654         int strncmp_result;
5655         static const char *limit = NULL;
5656         
5657         if (limit == NULL) {
5658                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5659                 if (limit_string != NULL) {
5660                         limit = limit_string;
5661                 } else {
5662                         limit = "";
5663                 }
5664         }
5665
5666         if (limit [0] != '\0') {
5667                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5668
5669                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5670                 g_free (caller_method_name);
5671         
5672                 //return (strncmp_result <= 0);
5673                 return (strncmp_result == 0);
5674         } else {
5675                 return TRUE;
5676         }
5677 }
5678 #endif
5679
5680 static void
5681 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5682 {
5683         static double r8_0 = 0.0;
5684         MonoInst *ins;
5685         int t;
5686
5687         rtype = mini_replace_type (rtype);
5688         t = rtype->type;
5689
5690         if (rtype->byref) {
5691                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5692         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5693                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5694         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5695                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5696         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5697                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5698                 ins->type = STACK_R8;
5699                 ins->inst_p0 = (void*)&r8_0;
5700                 ins->dreg = dreg;
5701                 MONO_ADD_INS (cfg->cbb, ins);
5702         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
5703                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
5704                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5705         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
5706                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
5707         } else {
5708                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5709         }
5710 }
5711
5712 static void
5713 emit_init_local (MonoCompile *cfg, int local, MonoType *type)
5714 {
5715         MonoInst *var = cfg->locals [local];
5716         if (COMPILE_SOFT_FLOAT (cfg)) {
5717                 MonoInst *store;
5718                 int reg = alloc_dreg (cfg, var->type);
5719                 emit_init_rvar (cfg, reg, type);
5720                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
5721         } else {
5722                 emit_init_rvar (cfg, var->dreg, type);
5723         }
5724 }
5725
5726 static int
5727 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5728                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5729 {
5730         MonoInst *ins, *rvar = NULL;
5731         MonoMethodHeader *cheader;
5732         MonoBasicBlock *ebblock, *sbblock;
5733         int i, costs;
5734         MonoMethod *prev_inlined_method;
5735         MonoInst **prev_locals, **prev_args;
5736         MonoType **prev_arg_types;
5737         guint prev_real_offset;
5738         GHashTable *prev_cbb_hash;
5739         MonoBasicBlock **prev_cil_offset_to_bb;
5740         MonoBasicBlock *prev_cbb;
5741         unsigned char* prev_cil_start;
5742         guint32 prev_cil_offset_to_bb_len;
5743         MonoMethod *prev_current_method;
5744         MonoGenericContext *prev_generic_context;
5745         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5746
5747         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5748
5749 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5750         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5751                 return 0;
5752 #endif
5753 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5754         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5755                 return 0;
5756 #endif
5757
5758         if (cfg->verbose_level > 2)
5759                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5760
5761         if (!cmethod->inline_info) {
5762                 cfg->stat_inlineable_methods++;
5763                 cmethod->inline_info = 1;
5764         }
5765
5766         /* allocate local variables */
5767         cheader = mono_method_get_header (cmethod);
5768
5769         if (cheader == NULL || mono_loader_get_last_error ()) {
5770                 MonoLoaderError *error = mono_loader_get_last_error ();
5771
5772                 if (cheader)
5773                         mono_metadata_free_mh (cheader);
5774                 if (inline_always && error)
5775                         mono_cfg_set_exception (cfg, error->exception_type);
5776
5777                 mono_loader_clear_error ();
5778                 return 0;
5779         }
5780
5781         /*Must verify before creating locals as it can cause the JIT to assert.*/
5782         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5783                 mono_metadata_free_mh (cheader);
5784                 return 0;
5785         }
5786
5787         /* allocate space to store the return value */
5788         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5789                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5790         }
5791
5792         prev_locals = cfg->locals;
5793         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5794         for (i = 0; i < cheader->num_locals; ++i)
5795                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5796
5797         /* allocate start and end blocks */
5798         /* This is needed so if the inline is aborted, we can clean up */
5799         NEW_BBLOCK (cfg, sbblock);
5800         sbblock->real_offset = real_offset;
5801
5802         NEW_BBLOCK (cfg, ebblock);
5803         ebblock->block_num = cfg->num_bblocks++;
5804         ebblock->real_offset = real_offset;
5805
5806         prev_args = cfg->args;
5807         prev_arg_types = cfg->arg_types;
5808         prev_inlined_method = cfg->inlined_method;
5809         cfg->inlined_method = cmethod;
5810         cfg->ret_var_set = FALSE;
5811         cfg->inline_depth ++;
5812         prev_real_offset = cfg->real_offset;
5813         prev_cbb_hash = cfg->cbb_hash;
5814         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
5815         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
5816         prev_cil_start = cfg->cil_start;
5817         prev_cbb = cfg->cbb;
5818         prev_current_method = cfg->current_method;
5819         prev_generic_context = cfg->generic_context;
5820         prev_ret_var_set = cfg->ret_var_set;
5821
5822         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
5823                 virtual = TRUE;
5824
5825         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
5826
5827         ret_var_set = cfg->ret_var_set;
5828
5829         cfg->inlined_method = prev_inlined_method;
5830         cfg->real_offset = prev_real_offset;
5831         cfg->cbb_hash = prev_cbb_hash;
5832         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
5833         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
5834         cfg->cil_start = prev_cil_start;
5835         cfg->locals = prev_locals;
5836         cfg->args = prev_args;
5837         cfg->arg_types = prev_arg_types;
5838         cfg->current_method = prev_current_method;
5839         cfg->generic_context = prev_generic_context;
5840         cfg->ret_var_set = prev_ret_var_set;
5841         cfg->inline_depth --;
5842
5843         if ((costs >= 0 && costs < 60) || inline_always) {
5844                 if (cfg->verbose_level > 2)
5845                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5846                 
5847                 cfg->stat_inlined_methods++;
5848
5849                 /* always add some code to avoid block split failures */
5850                 MONO_INST_NEW (cfg, ins, OP_NOP);
5851                 MONO_ADD_INS (prev_cbb, ins);
5852
5853                 prev_cbb->next_bb = sbblock;
5854                 link_bblock (cfg, prev_cbb, sbblock);
5855
5856                 /* 
5857                  * Get rid of the begin and end bblocks if possible to aid local
5858                  * optimizations.
5859                  */
5860                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
5861
5862                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
5863                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
5864
5865                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
5866                         MonoBasicBlock *prev = ebblock->in_bb [0];
5867                         mono_merge_basic_blocks (cfg, prev, ebblock);
5868                         cfg->cbb = prev;
5869                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
5870                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
5871                                 cfg->cbb = prev_cbb;
5872                         }
5873                 } else {
5874                         /* 
5875                          * Its possible that the rvar is set in some prev bblock, but not in others.
5876                          * (#1835).
5877                          */
5878                         if (rvar) {
5879                                 MonoBasicBlock *bb;
5880
5881                                 for (i = 0; i < ebblock->in_count; ++i) {
5882                                         bb = ebblock->in_bb [i];
5883
5884                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
5885                                                 cfg->cbb = bb;
5886
5887                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
5888                                         }
5889                                 }
5890                         }
5891
5892                         cfg->cbb = ebblock;
5893                 }
5894
5895                 if (rvar) {
5896                         /*
5897                          * If the inlined method contains only a throw, then the ret var is not 
5898                          * set, so set it to a dummy value.
5899                          */
5900                         if (!ret_var_set)
5901                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
5902
5903                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
5904                         *sp++ = ins;
5905                 }
5906                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5907                 return costs + 1;
5908         } else {
5909                 if (cfg->verbose_level > 2)
5910                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
5911                 cfg->exception_type = MONO_EXCEPTION_NONE;
5912                 mono_loader_clear_error ();
5913
5914                 /* This gets rid of the newly added bblocks */
5915                 cfg->cbb = prev_cbb;
5916         }
5917         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5918         return 0;
5919 }
5920
5921 /*
5922  * Some of these comments may well be out-of-date.
5923  * Design decisions: we do a single pass over the IL code (and we do bblock 
5924  * splitting/merging in the few cases when it's required: a back jump to an IL
5925  * address that was not already seen as bblock starting point).
5926  * Code is validated as we go (full verification is still better left to metadata/verify.c).
5927  * Complex operations are decomposed in simpler ones right away. We need to let the 
5928  * arch-specific code peek and poke inside this process somehow (except when the 
5929  * optimizations can take advantage of the full semantic info of coarse opcodes).
5930  * All the opcodes of the form opcode.s are 'normalized' to opcode.
5931  * MonoInst->opcode initially is the IL opcode or some simplification of that 
5932  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
5933  * opcode with value bigger than OP_LAST.
5934  * At this point the IR can be handed over to an interpreter, a dumb code generator
5935  * or to the optimizing code generator that will translate it to SSA form.
5936  *
5937  * Profiling directed optimizations.
5938  * We may compile by default with few or no optimizations and instrument the code
5939  * or the user may indicate what methods to optimize the most either in a config file
5940  * or through repeated runs where the compiler applies offline the optimizations to 
5941  * each method and then decides if it was worth it.
5942  */
5943
5944 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
5945 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
5946 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
5947 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
5948 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
5949 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
5950 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
5951 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
5952
5953 /* offset from br.s -> br like opcodes */
5954 #define BIG_BRANCH_OFFSET 13
5955
5956 static gboolean
5957 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
5958 {
5959         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
5960
5961         return b == NULL || b == bb;
5962 }
5963
5964 static int
5965 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
5966 {
5967         unsigned char *ip = start;
5968         unsigned char *target;
5969         int i;
5970         guint cli_addr;
5971         MonoBasicBlock *bblock;
5972         const MonoOpcode *opcode;
5973
5974         while (ip < end) {
5975                 cli_addr = ip - start;
5976                 i = mono_opcode_value ((const guint8 **)&ip, end);
5977                 if (i < 0)
5978                         UNVERIFIED;
5979                 opcode = &mono_opcodes [i];
5980                 switch (opcode->argument) {
5981                 case MonoInlineNone:
5982                         ip++; 
5983                         break;
5984                 case MonoInlineString:
5985                 case MonoInlineType:
5986                 case MonoInlineField:
5987                 case MonoInlineMethod:
5988                 case MonoInlineTok:
5989                 case MonoInlineSig:
5990                 case MonoShortInlineR:
5991                 case MonoInlineI:
5992                         ip += 5;
5993                         break;
5994                 case MonoInlineVar:
5995                         ip += 3;
5996                         break;
5997                 case MonoShortInlineVar:
5998                 case MonoShortInlineI:
5999                         ip += 2;
6000                         break;
6001                 case MonoShortInlineBrTarget:
6002                         target = start + cli_addr + 2 + (signed char)ip [1];
6003                         GET_BBLOCK (cfg, bblock, target);
6004                         ip += 2;
6005                         if (ip < end)
6006                                 GET_BBLOCK (cfg, bblock, ip);
6007                         break;
6008                 case MonoInlineBrTarget:
6009                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6010                         GET_BBLOCK (cfg, bblock, target);
6011                         ip += 5;
6012                         if (ip < end)
6013                                 GET_BBLOCK (cfg, bblock, ip);
6014                         break;
6015                 case MonoInlineSwitch: {
6016                         guint32 n = read32 (ip + 1);
6017                         guint32 j;
6018                         ip += 5;
6019                         cli_addr += 5 + 4 * n;
6020                         target = start + cli_addr;
6021                         GET_BBLOCK (cfg, bblock, target);
6022                         
6023                         for (j = 0; j < n; ++j) {
6024                                 target = start + cli_addr + (gint32)read32 (ip);
6025                                 GET_BBLOCK (cfg, bblock, target);
6026                                 ip += 4;
6027                         }
6028                         break;
6029                 }
6030                 case MonoInlineR:
6031                 case MonoInlineI8:
6032                         ip += 9;
6033                         break;
6034                 default:
6035                         g_assert_not_reached ();
6036                 }
6037
6038                 if (i == CEE_THROW) {
6039                         unsigned char *bb_start = ip - 1;
6040                         
6041                         /* Find the start of the bblock containing the throw */
6042                         bblock = NULL;
6043                         while ((bb_start >= start) && !bblock) {
6044                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6045                                 bb_start --;
6046                         }
6047                         if (bblock)
6048                                 bblock->out_of_line = 1;
6049                 }
6050         }
6051         return 0;
6052 unverified:
6053 exception_exit:
6054         *pos = ip;
6055         return 1;
6056 }
6057
6058 static inline MonoMethod *
6059 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6060 {
6061         MonoMethod *method;
6062
6063         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6064                 method = mono_method_get_wrapper_data (m, token);
6065                 if (context)
6066                         method = mono_class_inflate_generic_method (method, context);
6067         } else {
6068                 method = mono_get_method_full (m->klass->image, token, klass, context);
6069         }
6070
6071         return method;
6072 }
6073
6074 static inline MonoMethod *
6075 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6076 {
6077         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6078
6079         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6080                 return NULL;
6081
6082         return method;
6083 }
6084
6085 static inline MonoClass*
6086 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6087 {
6088         MonoClass *klass;
6089
6090         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6091                 klass = mono_method_get_wrapper_data (method, token);
6092                 if (context)
6093                         klass = mono_class_inflate_generic_class (klass, context);
6094         } else {
6095                 klass = mono_class_get_full (method->klass->image, token, context);
6096         }
6097         if (klass)
6098                 mono_class_init (klass);
6099         return klass;
6100 }
6101
6102 static inline MonoMethodSignature*
6103 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6104 {
6105         MonoMethodSignature *fsig;
6106
6107         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6108                 MonoError error;
6109
6110                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6111                 if (context) {
6112                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6113                         // FIXME:
6114                         g_assert (mono_error_ok (&error));
6115                 }
6116         } else {
6117                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6118         }
6119         return fsig;
6120 }
6121
6122 /*
6123  * Returns TRUE if the JIT should abort inlining because "callee"
6124  * is influenced by security attributes.
6125  */
6126 static
6127 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6128 {
6129         guint32 result;
6130         
6131         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6132                 return TRUE;
6133         }
6134         
6135         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6136         if (result == MONO_JIT_SECURITY_OK)
6137                 return FALSE;
6138
6139         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6140                 /* Generate code to throw a SecurityException before the actual call/link */
6141                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6142                 MonoInst *args [2];
6143
6144                 NEW_ICONST (cfg, args [0], 4);
6145                 NEW_METHODCONST (cfg, args [1], caller);
6146                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6147         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6148                  /* don't hide previous results */
6149                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6150                 cfg->exception_data = result;
6151                 return TRUE;
6152         }
6153         
6154         return FALSE;
6155 }
6156
6157 static MonoMethod*
6158 throw_exception (void)
6159 {
6160         static MonoMethod *method = NULL;
6161
6162         if (!method) {
6163                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6164                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6165         }
6166         g_assert (method);
6167         return method;
6168 }
6169
6170 static void
6171 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6172 {
6173         MonoMethod *thrower = throw_exception ();
6174         MonoInst *args [1];
6175
6176         EMIT_NEW_PCONST (cfg, args [0], ex);
6177         mono_emit_method_call (cfg, thrower, args, NULL);
6178 }
6179
6180 /*
6181  * Return the original method is a wrapper is specified. We can only access 
6182  * the custom attributes from the original method.
6183  */
6184 static MonoMethod*
6185 get_original_method (MonoMethod *method)
6186 {
6187         if (method->wrapper_type == MONO_WRAPPER_NONE)
6188                 return method;
6189
6190         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6191         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6192                 return NULL;
6193
6194         /* in other cases we need to find the original method */
6195         return mono_marshal_method_from_wrapper (method);
6196 }
6197
6198 static void
6199 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6200                                           MonoBasicBlock *bblock, unsigned char *ip)
6201 {
6202         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6203         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6204         if (ex)
6205                 emit_throw_exception (cfg, ex);
6206 }
6207
6208 static void
6209 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6210                                          MonoBasicBlock *bblock, unsigned char *ip)
6211 {
6212         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6213         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6214         if (ex)
6215                 emit_throw_exception (cfg, ex);
6216 }
6217
6218 /*
6219  * Check that the IL instructions at ip are the array initialization
6220  * sequence and return the pointer to the data and the size.
6221  */
6222 static const char*
6223 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6224 {
6225         /*
6226          * newarr[System.Int32]
6227          * dup
6228          * ldtoken field valuetype ...
6229          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6230          */
6231         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6232                 guint32 token = read32 (ip + 7);
6233                 guint32 field_token = read32 (ip + 2);
6234                 guint32 field_index = field_token & 0xffffff;
6235                 guint32 rva;
6236                 const char *data_ptr;
6237                 int size = 0;
6238                 MonoMethod *cmethod;
6239                 MonoClass *dummy_class;
6240                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6241                 int dummy_align;
6242
6243                 if (!field)
6244                         return NULL;
6245
6246                 *out_field_token = field_token;
6247
6248                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6249                 if (!cmethod)
6250                         return NULL;
6251                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6252                         return NULL;
6253                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6254                 case MONO_TYPE_BOOLEAN:
6255                 case MONO_TYPE_I1:
6256                 case MONO_TYPE_U1:
6257                         size = 1; break;
6258                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6259 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6260                 case MONO_TYPE_CHAR:
6261                 case MONO_TYPE_I2:
6262                 case MONO_TYPE_U2:
6263                         size = 2; break;
6264                 case MONO_TYPE_I4:
6265                 case MONO_TYPE_U4:
6266                 case MONO_TYPE_R4:
6267                         size = 4; break;
6268                 case MONO_TYPE_R8:
6269                 case MONO_TYPE_I8:
6270                 case MONO_TYPE_U8:
6271                         size = 8; break;
6272 #endif
6273                 default:
6274                         return NULL;
6275                 }
6276                 size *= len;
6277                 if (size > mono_type_size (field->type, &dummy_align))
6278                     return NULL;
6279                 *out_size = size;
6280                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6281                 if (!method->klass->image->dynamic) {
6282                         field_index = read32 (ip + 2) & 0xffffff;
6283                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6284                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6285                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6286                         /* for aot code we do the lookup on load */
6287                         if (aot && data_ptr)
6288                                 return GUINT_TO_POINTER (rva);
6289                 } else {
6290                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6291                         g_assert (!aot);
6292                         data_ptr = mono_field_get_data (field);
6293                 }
6294                 return data_ptr;
6295         }
6296         return NULL;
6297 }
6298
6299 static void
6300 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6301 {
6302         char *method_fname = mono_method_full_name (method, TRUE);
6303         char *method_code;
6304         MonoMethodHeader *header = mono_method_get_header (method);
6305
6306         if (header->code_size == 0)
6307                 method_code = g_strdup ("method body is empty.");
6308         else
6309                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6310         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6311         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6312         g_free (method_fname);
6313         g_free (method_code);
6314         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6315 }
6316
6317 static void
6318 set_exception_object (MonoCompile *cfg, MonoException *exception)
6319 {
6320         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6321         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6322         cfg->exception_ptr = exception;
6323 }
6324
6325 static void
6326 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6327 {
6328         MonoInst *ins;
6329         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6330         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6331                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6332                 /* Optimize reg-reg moves away */
6333                 /* 
6334                  * Can't optimize other opcodes, since sp[0] might point to
6335                  * the last ins of a decomposed opcode.
6336                  */
6337                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6338         } else {
6339                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6340         }
6341 }
6342
6343 /*
6344  * ldloca inhibits many optimizations so try to get rid of it in common
6345  * cases.
6346  */
6347 static inline unsigned char *
6348 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6349 {
6350         int local, token;
6351         MonoClass *klass;
6352         MonoType *type;
6353
6354         if (size == 1) {
6355                 local = ip [1];
6356                 ip += 2;
6357         } else {
6358                 local = read16 (ip + 2);
6359                 ip += 4;
6360         }
6361         
6362         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6363                 /* From the INITOBJ case */
6364                 token = read32 (ip + 2);
6365                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6366                 CHECK_TYPELOAD (klass);
6367                 type = mini_replace_type (&klass->byval_arg);
6368                 emit_init_local (cfg, local, type);
6369                 return ip + 6;
6370         }
6371 load_error:
6372         return NULL;
6373 }
6374
6375 static gboolean
6376 is_exception_class (MonoClass *class)
6377 {
6378         while (class) {
6379                 if (class == mono_defaults.exception_class)
6380                         return TRUE;
6381                 class = class->parent;
6382         }
6383         return FALSE;
6384 }
6385
6386 /*
6387  * is_jit_optimizer_disabled:
6388  *
6389  *   Determine whenever M's assembly has a DebuggableAttribute with the
6390  * IsJITOptimizerDisabled flag set.
6391  */
6392 static gboolean
6393 is_jit_optimizer_disabled (MonoMethod *m)
6394 {
6395         MonoAssembly *ass = m->klass->image->assembly;
6396         MonoCustomAttrInfo* attrs;
6397         static MonoClass *klass;
6398         int i;
6399         gboolean val = FALSE;
6400
6401         g_assert (ass);
6402         if (ass->jit_optimizer_disabled_inited)
6403                 return ass->jit_optimizer_disabled;
6404
6405         if (!klass)
6406                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6407         if (!klass) {
6408                 /* Linked away */
6409                 ass->jit_optimizer_disabled = FALSE;
6410                 mono_memory_barrier ();
6411                 ass->jit_optimizer_disabled_inited = TRUE;
6412                 return FALSE;
6413         }
6414
6415         attrs = mono_custom_attrs_from_assembly (ass);
6416         if (attrs) {
6417                 for (i = 0; i < attrs->num_attrs; ++i) {
6418                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6419                         const gchar *p;
6420                         int len;
6421                         MonoMethodSignature *sig;
6422
6423                         if (!attr->ctor || attr->ctor->klass != klass)
6424                                 continue;
6425                         /* Decode the attribute. See reflection.c */
6426                         len = attr->data_size;
6427                         p = (const char*)attr->data;
6428                         g_assert (read16 (p) == 0x0001);
6429                         p += 2;
6430
6431                         // FIXME: Support named parameters
6432                         sig = mono_method_signature (attr->ctor);
6433                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6434                                 continue;
6435                         /* Two boolean arguments */
6436                         p ++;
6437                         val = *p;
6438                 }
6439                 mono_custom_attrs_free (attrs);
6440         }
6441
6442         ass->jit_optimizer_disabled = val;
6443         mono_memory_barrier ();
6444         ass->jit_optimizer_disabled_inited = TRUE;
6445
6446         return val;
6447 }
6448
6449 static gboolean
6450 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6451 {
6452         gboolean supported_tail_call;
6453         int i;
6454
6455 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6456         supported_tail_call = mono_arch_tail_call_supported (mono_method_signature (method), mono_method_signature (cmethod));
6457 #else
6458         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6459 #endif
6460
6461         for (i = 0; i < fsig->param_count; ++i) {
6462                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6463                         /* These can point to the current method's stack */
6464                         supported_tail_call = FALSE;
6465         }
6466         if (fsig->hasthis && cmethod->klass->valuetype)
6467                 /* this might point to the current method's stack */
6468                 supported_tail_call = FALSE;
6469         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6470                 supported_tail_call = FALSE;
6471         if (cfg->method->save_lmf)
6472                 supported_tail_call = FALSE;
6473         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6474                 supported_tail_call = FALSE;
6475         if (call_opcode != CEE_CALL)
6476                 supported_tail_call = FALSE;
6477
6478         /* Debugging support */
6479 #if 0
6480         if (supported_tail_call) {
6481                 if (!mono_debug_count ())
6482                         supported_tail_call = FALSE;
6483         }
6484 #endif
6485
6486         return supported_tail_call;
6487 }
6488
6489 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6490  * it to the thread local value based on the tls_offset field. Every other kind of access to
6491  * the field causes an assert.
6492  */
6493 static gboolean
6494 is_magic_tls_access (MonoClassField *field)
6495 {
6496         if (strcmp (field->name, "tlsdata"))
6497                 return FALSE;
6498         if (strcmp (field->parent->name, "ThreadLocal`1"))
6499                 return FALSE;
6500         return field->parent->image == mono_defaults.corlib;
6501 }
6502
6503 /* emits the code needed to access a managed tls var (like ThreadStatic)
6504  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6505  * pointer for the current thread.
6506  * Returns the MonoInst* representing the address of the tls var.
6507  */
6508 static MonoInst*
6509 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6510 {
6511         MonoInst *addr;
6512         int static_data_reg, array_reg, dreg;
6513         int offset2_reg, idx_reg;
6514         // inlined access to the tls data
6515         // idx = (offset >> 24) - 1;
6516         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6517         static_data_reg = alloc_ireg (cfg);
6518         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6519         idx_reg = alloc_ireg (cfg);
6520         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6521         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6522         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6523         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6524         array_reg = alloc_ireg (cfg);
6525         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6526         offset2_reg = alloc_ireg (cfg);
6527         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6528         dreg = alloc_ireg (cfg);
6529         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6530         return addr;
6531 }
6532
6533 /*
6534  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6535  * this address is cached per-method in cached_tls_addr.
6536  */
6537 static MonoInst*
6538 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6539 {
6540         MonoInst *load, *addr, *temp, *store, *thread_ins;
6541         MonoClassField *offset_field;
6542
6543         if (*cached_tls_addr) {
6544                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6545                 return addr;
6546         }
6547         thread_ins = mono_get_thread_intrinsic (cfg);
6548         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6549
6550         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6551         if (thread_ins) {
6552                 MONO_ADD_INS (cfg->cbb, thread_ins);
6553         } else {
6554                 MonoMethod *thread_method;
6555                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6556                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6557         }
6558         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6559         addr->klass = mono_class_from_mono_type (tls_field->type);
6560         addr->type = STACK_MP;
6561         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6562         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6563
6564         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6565         return addr;
6566 }
6567
6568 /*
6569  * mono_method_to_ir:
6570  *
6571  *   Translate the .net IL into linear IR.
6572  */
6573 int
6574 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6575                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6576                    guint inline_offset, gboolean is_virtual_call)
6577 {
6578         MonoError error;
6579         MonoInst *ins, **sp, **stack_start;
6580         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6581         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6582         MonoMethod *cmethod, *method_definition;
6583         MonoInst **arg_array;
6584         MonoMethodHeader *header;
6585         MonoImage *image;
6586         guint32 token, ins_flag;
6587         MonoClass *klass;
6588         MonoClass *constrained_call = NULL;
6589         unsigned char *ip, *end, *target, *err_pos;
6590         MonoMethodSignature *sig;
6591         MonoGenericContext *generic_context = NULL;
6592         MonoGenericContainer *generic_container = NULL;
6593         MonoType **param_types;
6594         int i, n, start_new_bblock, dreg;
6595         int num_calls = 0, inline_costs = 0;
6596         int breakpoint_id = 0;
6597         guint num_args;
6598         MonoBoolean security, pinvoke;
6599         MonoSecurityManager* secman = NULL;
6600         MonoDeclSecurityActions actions;
6601         GSList *class_inits = NULL;
6602         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6603         int context_used;
6604         gboolean init_locals, seq_points, skip_dead_blocks;
6605         gboolean disable_inline, sym_seq_points = FALSE;
6606         MonoInst *cached_tls_addr = NULL;
6607         MonoDebugMethodInfo *minfo;
6608         MonoBitSet *seq_point_locs = NULL;
6609         MonoBitSet *seq_point_set_locs = NULL;
6610
6611         disable_inline = is_jit_optimizer_disabled (method);
6612
6613         /* serialization and xdomain stuff may need access to private fields and methods */
6614         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6615         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6616         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6617         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6618         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6619         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6620
6621         dont_verify |= mono_security_smcs_hack_enabled ();
6622
6623         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6624         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6625         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6626         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6627         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6628
6629         image = method->klass->image;
6630         header = mono_method_get_header (method);
6631         if (!header) {
6632                 MonoLoaderError *error;
6633
6634                 if ((error = mono_loader_get_last_error ())) {
6635                         mono_cfg_set_exception (cfg, error->exception_type);
6636                 } else {
6637                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6638                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6639                 }
6640                 goto exception_exit;
6641         }
6642         generic_container = mono_method_get_generic_container (method);
6643         sig = mono_method_signature (method);
6644         num_args = sig->hasthis + sig->param_count;
6645         ip = (unsigned char*)header->code;
6646         cfg->cil_start = ip;
6647         end = ip + header->code_size;
6648         cfg->stat_cil_code_size += header->code_size;
6649         init_locals = header->init_locals;
6650
6651         seq_points = cfg->gen_seq_points && cfg->method == method;
6652 #ifdef PLATFORM_ANDROID
6653         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6654 #endif
6655
6656         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6657                 /* We could hit a seq point before attaching to the JIT (#8338) */
6658                 seq_points = FALSE;
6659         }
6660
6661         if (cfg->gen_seq_points && cfg->method == method) {
6662                 minfo = mono_debug_lookup_method (method);
6663                 if (minfo) {
6664                         int i, n_il_offsets;
6665                         int *il_offsets;
6666                         int *line_numbers;
6667
6668                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6669                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6670                         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);
6671                         sym_seq_points = TRUE;
6672                         for (i = 0; i < n_il_offsets; ++i) {
6673                                 if (il_offsets [i] < header->code_size)
6674                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6675                         }
6676                         g_free (il_offsets);
6677                         g_free (line_numbers);
6678                 }
6679         }
6680
6681         /* 
6682          * Methods without init_locals set could cause asserts in various passes
6683          * (#497220).
6684          */
6685         init_locals = TRUE;
6686
6687         method_definition = method;
6688         while (method_definition->is_inflated) {
6689                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6690                 method_definition = imethod->declaring;
6691         }
6692
6693         /* SkipVerification is not allowed if core-clr is enabled */
6694         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6695                 dont_verify = TRUE;
6696                 dont_verify_stloc = TRUE;
6697         }
6698
6699         if (sig->is_inflated)
6700                 generic_context = mono_method_get_context (method);
6701         else if (generic_container)
6702                 generic_context = &generic_container->context;
6703         cfg->generic_context = generic_context;
6704
6705         if (!cfg->generic_sharing_context)
6706                 g_assert (!sig->has_type_parameters);
6707
6708         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6709                 g_assert (method->is_inflated);
6710                 g_assert (mono_method_get_context (method)->method_inst);
6711         }
6712         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6713                 g_assert (sig->generic_param_count);
6714
6715         if (cfg->method == method) {
6716                 cfg->real_offset = 0;
6717         } else {
6718                 cfg->real_offset = inline_offset;
6719         }
6720
6721         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6722         cfg->cil_offset_to_bb_len = header->code_size;
6723
6724         cfg->current_method = method;
6725
6726         if (cfg->verbose_level > 2)
6727                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6728
6729         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6730         if (sig->hasthis)
6731                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6732         for (n = 0; n < sig->param_count; ++n)
6733                 param_types [n + sig->hasthis] = sig->params [n];
6734         cfg->arg_types = param_types;
6735
6736         dont_inline = g_list_prepend (dont_inline, method);
6737         if (cfg->method == method) {
6738
6739                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6740                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6741
6742                 /* ENTRY BLOCK */
6743                 NEW_BBLOCK (cfg, start_bblock);
6744                 cfg->bb_entry = start_bblock;
6745                 start_bblock->cil_code = NULL;
6746                 start_bblock->cil_length = 0;
6747 #if defined(__native_client_codegen__)
6748                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6749                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6750                 MONO_ADD_INS (start_bblock, ins);
6751 #endif
6752
6753                 /* EXIT BLOCK */
6754                 NEW_BBLOCK (cfg, end_bblock);
6755                 cfg->bb_exit = end_bblock;
6756                 end_bblock->cil_code = NULL;
6757                 end_bblock->cil_length = 0;
6758                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6759                 g_assert (cfg->num_bblocks == 2);
6760
6761                 arg_array = cfg->args;
6762
6763                 if (header->num_clauses) {
6764                         cfg->spvars = g_hash_table_new (NULL, NULL);
6765                         cfg->exvars = g_hash_table_new (NULL, NULL);
6766                 }
6767                 /* handle exception clauses */
6768                 for (i = 0; i < header->num_clauses; ++i) {
6769                         MonoBasicBlock *try_bb;
6770                         MonoExceptionClause *clause = &header->clauses [i];
6771                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6772                         try_bb->real_offset = clause->try_offset;
6773                         try_bb->try_start = TRUE;
6774                         try_bb->region = ((i + 1) << 8) | clause->flags;
6775                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6776                         tblock->real_offset = clause->handler_offset;
6777                         tblock->flags |= BB_EXCEPTION_HANDLER;
6778
6779                         /*
6780                          * Linking the try block with the EH block hinders inlining as we won't be able to 
6781                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
6782                          */
6783                         if (COMPILE_LLVM (cfg))
6784                                 link_bblock (cfg, try_bb, tblock);
6785
6786                         if (*(ip + clause->handler_offset) == CEE_POP)
6787                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6788
6789                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6790                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6791                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6792                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6793                                 MONO_ADD_INS (tblock, ins);
6794
6795                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6796                                         /* finally clauses already have a seq point */
6797                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6798                                         MONO_ADD_INS (tblock, ins);
6799                                 }
6800
6801                                 /* todo: is a fault block unsafe to optimize? */
6802                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6803                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
6804                         }
6805
6806
6807                         /*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);
6808                           while (p < end) {
6809                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
6810                           }*/
6811                         /* catch and filter blocks get the exception object on the stack */
6812                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
6813                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6814                                 MonoInst *dummy_use;
6815
6816                                 /* mostly like handle_stack_args (), but just sets the input args */
6817                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
6818                                 tblock->in_scount = 1;
6819                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6820                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6821
6822                                 /* 
6823                                  * Add a dummy use for the exvar so its liveness info will be
6824                                  * correct.
6825                                  */
6826                                 cfg->cbb = tblock;
6827                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
6828                                 
6829                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6830                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
6831                                         tblock->flags |= BB_EXCEPTION_HANDLER;
6832                                         tblock->real_offset = clause->data.filter_offset;
6833                                         tblock->in_scount = 1;
6834                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6835                                         /* The filter block shares the exvar with the handler block */
6836                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6837                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6838                                         MONO_ADD_INS (tblock, ins);
6839                                 }
6840                         }
6841
6842                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
6843                                         clause->data.catch_class &&
6844                                         cfg->generic_sharing_context &&
6845                                         mono_class_check_context_used (clause->data.catch_class)) {
6846                                 /*
6847                                  * In shared generic code with catch
6848                                  * clauses containing type variables
6849                                  * the exception handling code has to
6850                                  * be able to get to the rgctx.
6851                                  * Therefore we have to make sure that
6852                                  * the vtable/mrgctx argument (for
6853                                  * static or generic methods) or the
6854                                  * "this" argument (for non-static
6855                                  * methods) are live.
6856                                  */
6857                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6858                                                 mini_method_get_context (method)->method_inst ||
6859                                                 method->klass->valuetype) {
6860                                         mono_get_vtable_var (cfg);
6861                                 } else {
6862                                         MonoInst *dummy_use;
6863
6864                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
6865                                 }
6866                         }
6867                 }
6868         } else {
6869                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
6870                 cfg->cbb = start_bblock;
6871                 cfg->args = arg_array;
6872                 mono_save_args (cfg, sig, inline_args);
6873         }
6874
6875         /* FIRST CODE BLOCK */
6876         NEW_BBLOCK (cfg, bblock);
6877         bblock->cil_code = ip;
6878         cfg->cbb = bblock;
6879         cfg->ip = ip;
6880
6881         ADD_BBLOCK (cfg, bblock);
6882
6883         if (cfg->method == method) {
6884                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
6885                 if (breakpoint_id) {
6886                         MONO_INST_NEW (cfg, ins, OP_BREAK);
6887                         MONO_ADD_INS (bblock, ins);
6888                 }
6889         }
6890
6891         if (mono_security_cas_enabled ())
6892                 secman = mono_security_manager_get_methods ();
6893
6894         security = (secman && mono_security_method_has_declsec (method));
6895         /* at this point having security doesn't mean we have any code to generate */
6896         if (security && (cfg->method == method)) {
6897                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
6898                  * And we do not want to enter the next section (with allocation) if we
6899                  * have nothing to generate */
6900                 security = mono_declsec_get_demands (method, &actions);
6901         }
6902
6903         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
6904         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
6905         if (pinvoke) {
6906                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6907                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6908                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
6909
6910                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
6911                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6912                                 pinvoke = FALSE;
6913                         }
6914                         if (custom)
6915                                 mono_custom_attrs_free (custom);
6916
6917                         if (pinvoke) {
6918                                 custom = mono_custom_attrs_from_class (wrapped->klass);
6919                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6920                                         pinvoke = FALSE;
6921                                 }
6922                                 if (custom)
6923                                         mono_custom_attrs_free (custom);
6924                         }
6925                 } else {
6926                         /* not a P/Invoke after all */
6927                         pinvoke = FALSE;
6928                 }
6929         }
6930         
6931         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
6932                 /* we use a separate basic block for the initialization code */
6933                 NEW_BBLOCK (cfg, init_localsbb);
6934                 cfg->bb_init = init_localsbb;
6935                 init_localsbb->real_offset = cfg->real_offset;
6936                 start_bblock->next_bb = init_localsbb;
6937                 init_localsbb->next_bb = bblock;
6938                 link_bblock (cfg, start_bblock, init_localsbb);
6939                 link_bblock (cfg, init_localsbb, bblock);
6940                 
6941                 cfg->cbb = init_localsbb;
6942         } else {
6943                 start_bblock->next_bb = bblock;
6944                 link_bblock (cfg, start_bblock, bblock);
6945         }
6946
6947         if (cfg->gsharedvt && cfg->method == method) {
6948                 MonoGSharedVtMethodInfo *info;
6949                 MonoInst *var, *locals_var;
6950                 int dreg;
6951
6952                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
6953                 info->method = cfg->method;
6954                 // FIXME: Free this
6955                 info->entries = g_ptr_array_new ();
6956                 cfg->gsharedvt_info = info;
6957
6958                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6959                 /* prevent it from being register allocated */
6960                 //var->flags |= MONO_INST_VOLATILE;
6961                 cfg->gsharedvt_info_var = var;
6962
6963                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
6964                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
6965
6966                 /* Allocate locals */
6967                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6968                 /* prevent it from being register allocated */
6969                 //locals_var->flags |= MONO_INST_VOLATILE;
6970                 cfg->gsharedvt_locals_var = locals_var;
6971
6972                 dreg = alloc_ireg (cfg);
6973                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
6974
6975                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
6976                 ins->dreg = locals_var->dreg;
6977                 ins->sreg1 = dreg;
6978                 MONO_ADD_INS (cfg->cbb, ins);
6979                 cfg->gsharedvt_locals_var_ins = ins;
6980                 
6981                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
6982                 /*
6983                 if (init_locals)
6984                         ins->flags |= MONO_INST_INIT;
6985                 */
6986         }
6987
6988         /* at this point we know, if security is TRUE, that some code needs to be generated */
6989         if (security && (cfg->method == method)) {
6990                 MonoInst *args [2];
6991
6992                 cfg->stat_cas_demand_generation++;
6993
6994                 if (actions.demand.blob) {
6995                         /* Add code for SecurityAction.Demand */
6996                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
6997                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
6998                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
6999                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7000                 }
7001                 if (actions.noncasdemand.blob) {
7002                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7003                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7004                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7005                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7006                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7007                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7008                 }
7009                 if (actions.demandchoice.blob) {
7010                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7011                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7012                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7013                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7014                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7015                 }
7016         }
7017
7018         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7019         if (pinvoke) {
7020                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7021         }
7022
7023         if (mono_security_core_clr_enabled ()) {
7024                 /* check if this is native code, e.g. an icall or a p/invoke */
7025                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7026                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7027                         if (wrapped) {
7028                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7029                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7030
7031                                 /* if this ia a native call then it can only be JITted from platform code */
7032                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7033                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7034                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7035                                                         mono_get_exception_method_access ();
7036                                                 emit_throw_exception (cfg, ex);
7037                                         }
7038                                 }
7039                         }
7040                 }
7041         }
7042
7043         CHECK_CFG_EXCEPTION;
7044
7045         if (header->code_size == 0)
7046                 UNVERIFIED;
7047
7048         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7049                 ip = err_pos;
7050                 UNVERIFIED;
7051         }
7052
7053         if (cfg->method == method)
7054                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7055
7056         for (n = 0; n < header->num_locals; ++n) {
7057                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7058                         UNVERIFIED;
7059         }
7060         class_inits = NULL;
7061
7062         /* We force the vtable variable here for all shared methods
7063            for the possibility that they might show up in a stack
7064            trace where their exact instantiation is needed. */
7065         if (cfg->generic_sharing_context && method == cfg->method) {
7066                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7067                                 mini_method_get_context (method)->method_inst ||
7068                                 method->klass->valuetype) {
7069                         mono_get_vtable_var (cfg);
7070                 } else {
7071                         /* FIXME: Is there a better way to do this?
7072                            We need the variable live for the duration
7073                            of the whole method. */
7074                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7075                 }
7076         }
7077
7078         /* add a check for this != NULL to inlined methods */
7079         if (is_virtual_call) {
7080                 MonoInst *arg_ins;
7081
7082                 NEW_ARGLOAD (cfg, arg_ins, 0);
7083                 MONO_ADD_INS (cfg->cbb, arg_ins);
7084                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7085         }
7086
7087         skip_dead_blocks = !dont_verify;
7088         if (skip_dead_blocks) {
7089                 original_bb = bb = mono_basic_block_split (method, &error);
7090                 if (!mono_error_ok (&error)) {
7091                         mono_error_cleanup (&error);
7092                         UNVERIFIED;
7093                 }
7094                 g_assert (bb);
7095         }
7096
7097         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7098         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7099
7100         ins_flag = 0;
7101         start_new_bblock = 0;
7102         cfg->cbb = bblock;
7103         while (ip < end) {
7104                 if (cfg->method == method)
7105                         cfg->real_offset = ip - header->code;
7106                 else
7107                         cfg->real_offset = inline_offset;
7108                 cfg->ip = ip;
7109
7110                 context_used = 0;
7111                 
7112                 if (start_new_bblock) {
7113                         bblock->cil_length = ip - bblock->cil_code;
7114                         if (start_new_bblock == 2) {
7115                                 g_assert (ip == tblock->cil_code);
7116                         } else {
7117                                 GET_BBLOCK (cfg, tblock, ip);
7118                         }
7119                         bblock->next_bb = tblock;
7120                         bblock = tblock;
7121                         cfg->cbb = bblock;
7122                         start_new_bblock = 0;
7123                         for (i = 0; i < bblock->in_scount; ++i) {
7124                                 if (cfg->verbose_level > 3)
7125                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7126                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7127                                 *sp++ = ins;
7128                         }
7129                         if (class_inits)
7130                                 g_slist_free (class_inits);
7131                         class_inits = NULL;
7132                 } else {
7133                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7134                                 link_bblock (cfg, bblock, tblock);
7135                                 if (sp != stack_start) {
7136                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7137                                         sp = stack_start;
7138                                         CHECK_UNVERIFIABLE (cfg);
7139                                 }
7140                                 bblock->next_bb = tblock;
7141                                 bblock = tblock;
7142                                 cfg->cbb = bblock;
7143                                 for (i = 0; i < bblock->in_scount; ++i) {
7144                                         if (cfg->verbose_level > 3)
7145                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7146                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7147                                         *sp++ = ins;
7148                                 }
7149                                 g_slist_free (class_inits);
7150                                 class_inits = NULL;
7151                         }
7152                 }
7153
7154                 if (skip_dead_blocks) {
7155                         int ip_offset = ip - header->code;
7156
7157                         if (ip_offset == bb->end)
7158                                 bb = bb->next;
7159
7160                         if (bb->dead) {
7161                                 int op_size = mono_opcode_size (ip, end);
7162                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7163
7164                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7165
7166                                 if (ip_offset + op_size == bb->end) {
7167                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7168                                         MONO_ADD_INS (bblock, ins);
7169                                         start_new_bblock = 1;
7170                                 }
7171
7172                                 ip += op_size;
7173                                 continue;
7174                         }
7175                 }
7176                 /*
7177                  * Sequence points are points where the debugger can place a breakpoint.
7178                  * Currently, we generate these automatically at points where the IL
7179                  * stack is empty.
7180                  */
7181                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7182                         /*
7183                          * Make methods interruptable at the beginning, and at the targets of
7184                          * backward branches.
7185                          * Also, do this at the start of every bblock in methods with clauses too,
7186                          * to be able to handle instructions with inprecise control flow like
7187                          * throw/endfinally.
7188                          * Backward branches are handled at the end of method-to-ir ().
7189                          */
7190                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7191
7192                         /* Avoid sequence points on empty IL like .volatile */
7193                         // FIXME: Enable this
7194                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7195                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7196                         if (sp != stack_start)
7197                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7198                         MONO_ADD_INS (cfg->cbb, ins);
7199
7200                         if (sym_seq_points)
7201                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7202                 }
7203
7204                 bblock->real_offset = cfg->real_offset;
7205
7206                 if ((cfg->method == method) && cfg->coverage_info) {
7207                         guint32 cil_offset = ip - header->code;
7208                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7209
7210                         /* TODO: Use an increment here */
7211 #if defined(TARGET_X86)
7212                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7213                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7214                         ins->inst_imm = 1;
7215                         MONO_ADD_INS (cfg->cbb, ins);
7216 #else
7217                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7218                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7219 #endif
7220                 }
7221
7222                 if (cfg->verbose_level > 3)
7223                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7224
7225                 switch (*ip) {
7226                 case CEE_NOP:
7227                         if (seq_points && !sym_seq_points && sp != stack_start) {
7228                                 /*
7229                                  * The C# compiler uses these nops to notify the JIT that it should
7230                                  * insert seq points.
7231                                  */
7232                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7233                                 MONO_ADD_INS (cfg->cbb, ins);
7234                         }
7235                         if (cfg->keep_cil_nops)
7236                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7237                         else
7238                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7239                         ip++;
7240                         MONO_ADD_INS (bblock, ins);
7241                         break;
7242                 case CEE_BREAK:
7243                         if (should_insert_brekpoint (cfg->method)) {
7244                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7245                         } else {
7246                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7247                         }
7248                         ip++;
7249                         MONO_ADD_INS (bblock, ins);
7250                         break;
7251                 case CEE_LDARG_0:
7252                 case CEE_LDARG_1:
7253                 case CEE_LDARG_2:
7254                 case CEE_LDARG_3:
7255                         CHECK_STACK_OVF (1);
7256                         n = (*ip)-CEE_LDARG_0;
7257                         CHECK_ARG (n);
7258                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7259                         ip++;
7260                         *sp++ = ins;
7261                         break;
7262                 case CEE_LDLOC_0:
7263                 case CEE_LDLOC_1:
7264                 case CEE_LDLOC_2:
7265                 case CEE_LDLOC_3:
7266                         CHECK_STACK_OVF (1);
7267                         n = (*ip)-CEE_LDLOC_0;
7268                         CHECK_LOCAL (n);
7269                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7270                         ip++;
7271                         *sp++ = ins;
7272                         break;
7273                 case CEE_STLOC_0:
7274                 case CEE_STLOC_1:
7275                 case CEE_STLOC_2:
7276                 case CEE_STLOC_3: {
7277                         CHECK_STACK (1);
7278                         n = (*ip)-CEE_STLOC_0;
7279                         CHECK_LOCAL (n);
7280                         --sp;
7281                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7282                                 UNVERIFIED;
7283                         emit_stloc_ir (cfg, sp, header, n);
7284                         ++ip;
7285                         inline_costs += 1;
7286                         break;
7287                         }
7288                 case CEE_LDARG_S:
7289                         CHECK_OPSIZE (2);
7290                         CHECK_STACK_OVF (1);
7291                         n = ip [1];
7292                         CHECK_ARG (n);
7293                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7294                         *sp++ = ins;
7295                         ip += 2;
7296                         break;
7297                 case CEE_LDARGA_S:
7298                         CHECK_OPSIZE (2);
7299                         CHECK_STACK_OVF (1);
7300                         n = ip [1];
7301                         CHECK_ARG (n);
7302                         NEW_ARGLOADA (cfg, ins, n);
7303                         MONO_ADD_INS (cfg->cbb, ins);
7304                         *sp++ = ins;
7305                         ip += 2;
7306                         break;
7307                 case CEE_STARG_S:
7308                         CHECK_OPSIZE (2);
7309                         CHECK_STACK (1);
7310                         --sp;
7311                         n = ip [1];
7312                         CHECK_ARG (n);
7313                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7314                                 UNVERIFIED;
7315                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7316                         ip += 2;
7317                         break;
7318                 case CEE_LDLOC_S:
7319                         CHECK_OPSIZE (2);
7320                         CHECK_STACK_OVF (1);
7321                         n = ip [1];
7322                         CHECK_LOCAL (n);
7323                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7324                         *sp++ = ins;
7325                         ip += 2;
7326                         break;
7327                 case CEE_LDLOCA_S: {
7328                         unsigned char *tmp_ip;
7329                         CHECK_OPSIZE (2);
7330                         CHECK_STACK_OVF (1);
7331                         CHECK_LOCAL (ip [1]);
7332
7333                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7334                                 ip = tmp_ip;
7335                                 inline_costs += 1;
7336                                 break;
7337                         }
7338
7339                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7340                         *sp++ = ins;
7341                         ip += 2;
7342                         break;
7343                 }
7344                 case CEE_STLOC_S:
7345                         CHECK_OPSIZE (2);
7346                         CHECK_STACK (1);
7347                         --sp;
7348                         CHECK_LOCAL (ip [1]);
7349                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7350                                 UNVERIFIED;
7351                         emit_stloc_ir (cfg, sp, header, ip [1]);
7352                         ip += 2;
7353                         inline_costs += 1;
7354                         break;
7355                 case CEE_LDNULL:
7356                         CHECK_STACK_OVF (1);
7357                         EMIT_NEW_PCONST (cfg, ins, NULL);
7358                         ins->type = STACK_OBJ;
7359                         ++ip;
7360                         *sp++ = ins;
7361                         break;
7362                 case CEE_LDC_I4_M1:
7363                         CHECK_STACK_OVF (1);
7364                         EMIT_NEW_ICONST (cfg, ins, -1);
7365                         ++ip;
7366                         *sp++ = ins;
7367                         break;
7368                 case CEE_LDC_I4_0:
7369                 case CEE_LDC_I4_1:
7370                 case CEE_LDC_I4_2:
7371                 case CEE_LDC_I4_3:
7372                 case CEE_LDC_I4_4:
7373                 case CEE_LDC_I4_5:
7374                 case CEE_LDC_I4_6:
7375                 case CEE_LDC_I4_7:
7376                 case CEE_LDC_I4_8:
7377                         CHECK_STACK_OVF (1);
7378                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7379                         ++ip;
7380                         *sp++ = ins;
7381                         break;
7382                 case CEE_LDC_I4_S:
7383                         CHECK_OPSIZE (2);
7384                         CHECK_STACK_OVF (1);
7385                         ++ip;
7386                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7387                         ++ip;
7388                         *sp++ = ins;
7389                         break;
7390                 case CEE_LDC_I4:
7391                         CHECK_OPSIZE (5);
7392                         CHECK_STACK_OVF (1);
7393                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7394                         ip += 5;
7395                         *sp++ = ins;
7396                         break;
7397                 case CEE_LDC_I8:
7398                         CHECK_OPSIZE (9);
7399                         CHECK_STACK_OVF (1);
7400                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7401                         ins->type = STACK_I8;
7402                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7403                         ++ip;
7404                         ins->inst_l = (gint64)read64 (ip);
7405                         MONO_ADD_INS (bblock, ins);
7406                         ip += 8;
7407                         *sp++ = ins;
7408                         break;
7409                 case CEE_LDC_R4: {
7410                         float *f;
7411                         gboolean use_aotconst = FALSE;
7412
7413 #ifdef TARGET_POWERPC
7414                         /* FIXME: Clean this up */
7415                         if (cfg->compile_aot)
7416                                 use_aotconst = TRUE;
7417 #endif
7418
7419                         /* FIXME: we should really allocate this only late in the compilation process */
7420                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7421                         CHECK_OPSIZE (5);
7422                         CHECK_STACK_OVF (1);
7423
7424                         if (use_aotconst) {
7425                                 MonoInst *cons;
7426                                 int dreg;
7427
7428                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7429
7430                                 dreg = alloc_freg (cfg);
7431                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7432                                 ins->type = STACK_R8;
7433                         } else {
7434                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7435                                 ins->type = STACK_R8;
7436                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7437                                 ins->inst_p0 = f;
7438                                 MONO_ADD_INS (bblock, ins);
7439                         }
7440                         ++ip;
7441                         readr4 (ip, f);
7442                         ip += 4;
7443                         *sp++ = ins;                    
7444                         break;
7445                 }
7446                 case CEE_LDC_R8: {
7447                         double *d;
7448                         gboolean use_aotconst = FALSE;
7449
7450 #ifdef TARGET_POWERPC
7451                         /* FIXME: Clean this up */
7452                         if (cfg->compile_aot)
7453                                 use_aotconst = TRUE;
7454 #endif
7455
7456                         /* FIXME: we should really allocate this only late in the compilation process */
7457                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7458                         CHECK_OPSIZE (9);
7459                         CHECK_STACK_OVF (1);
7460
7461                         if (use_aotconst) {
7462                                 MonoInst *cons;
7463                                 int dreg;
7464
7465                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7466
7467                                 dreg = alloc_freg (cfg);
7468                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7469                                 ins->type = STACK_R8;
7470                         } else {
7471                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7472                                 ins->type = STACK_R8;
7473                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7474                                 ins->inst_p0 = d;
7475                                 MONO_ADD_INS (bblock, ins);
7476                         }
7477                         ++ip;
7478                         readr8 (ip, d);
7479                         ip += 8;
7480                         *sp++ = ins;
7481                         break;
7482                 }
7483                 case CEE_DUP: {
7484                         MonoInst *temp, *store;
7485                         CHECK_STACK (1);
7486                         CHECK_STACK_OVF (1);
7487                         sp--;
7488                         ins = *sp;
7489
7490                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7491                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7492
7493                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7494                         *sp++ = ins;
7495
7496                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7497                         *sp++ = ins;
7498
7499                         ++ip;
7500                         inline_costs += 2;
7501                         break;
7502                 }
7503                 case CEE_POP:
7504                         CHECK_STACK (1);
7505                         ip++;
7506                         --sp;
7507
7508 #ifdef TARGET_X86
7509                         if (sp [0]->type == STACK_R8)
7510                                 /* we need to pop the value from the x86 FP stack */
7511                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7512 #endif
7513                         break;
7514                 case CEE_JMP: {
7515                         MonoCallInst *call;
7516
7517                         INLINE_FAILURE ("jmp");
7518                         GSHAREDVT_FAILURE (*ip);
7519
7520                         CHECK_OPSIZE (5);
7521                         if (stack_start != sp)
7522                                 UNVERIFIED;
7523                         token = read32 (ip + 1);
7524                         /* FIXME: check the signature matches */
7525                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7526
7527                         if (!cmethod || mono_loader_get_last_error ())
7528                                 LOAD_ERROR;
7529  
7530                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7531                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7532
7533                         if (mono_security_cas_enabled ())
7534                                 CHECK_CFG_EXCEPTION;
7535
7536                         if (ARCH_HAVE_OP_TAIL_CALL) {
7537                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7538                                 int i, n;
7539
7540                                 /* Handle tail calls similarly to calls */
7541                                 n = fsig->param_count + fsig->hasthis;
7542
7543                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7544                                 call->method = cmethod;
7545                                 call->tail_call = TRUE;
7546                                 call->signature = mono_method_signature (cmethod);
7547                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7548                                 call->inst.inst_p0 = cmethod;
7549                                 for (i = 0; i < n; ++i)
7550                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7551
7552                                 mono_arch_emit_call (cfg, call);
7553                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7554                         } else {
7555                                 for (i = 0; i < num_args; ++i)
7556                                         /* Prevent arguments from being optimized away */
7557                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7558
7559                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7560                                 ins = (MonoInst*)call;
7561                                 ins->inst_p0 = cmethod;
7562                                 MONO_ADD_INS (bblock, ins);
7563                         }
7564
7565                         ip += 5;
7566                         start_new_bblock = 1;
7567                         break;
7568                 }
7569                 case CEE_CALLI:
7570                 case CEE_CALL:
7571                 case CEE_CALLVIRT: {
7572                         MonoInst *addr = NULL;
7573                         MonoMethodSignature *fsig = NULL;
7574                         int array_rank = 0;
7575                         int virtual = *ip == CEE_CALLVIRT;
7576                         int calli = *ip == CEE_CALLI;
7577                         gboolean pass_imt_from_rgctx = FALSE;
7578                         MonoInst *imt_arg = NULL;
7579                         MonoInst *keep_this_alive = NULL;
7580                         gboolean pass_vtable = FALSE;
7581                         gboolean pass_mrgctx = FALSE;
7582                         MonoInst *vtable_arg = NULL;
7583                         gboolean check_this = FALSE;
7584                         gboolean supported_tail_call = FALSE;
7585                         gboolean tail_call = FALSE;
7586                         gboolean need_seq_point = FALSE;
7587                         guint32 call_opcode = *ip;
7588                         gboolean emit_widen = TRUE;
7589                         gboolean push_res = TRUE;
7590                         gboolean skip_ret = FALSE;
7591                         gboolean delegate_invoke = FALSE;
7592
7593                         CHECK_OPSIZE (5);
7594                         token = read32 (ip + 1);
7595
7596                         ins = NULL;
7597
7598                         if (calli) {
7599                                 //GSHAREDVT_FAILURE (*ip);
7600                                 cmethod = NULL;
7601                                 CHECK_STACK (1);
7602                                 --sp;
7603                                 addr = *sp;
7604                                 fsig = mini_get_signature (method, token, generic_context);
7605                                 n = fsig->param_count + fsig->hasthis;
7606
7607                                 if (method->dynamic && fsig->pinvoke) {
7608                                         MonoInst *args [3];
7609
7610                                         /*
7611                                          * This is a call through a function pointer using a pinvoke
7612                                          * signature. Have to create a wrapper and call that instead.
7613                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7614                                          * instead based on the signature.
7615                                          */
7616                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7617                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7618                                         args [2] = addr;
7619                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7620                                 }
7621                         } else {
7622                                 MonoMethod *cil_method;
7623
7624                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7625                                 cil_method = cmethod;
7626                                 
7627                                 if (constrained_call) {
7628                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7629                                                 if (cfg->verbose_level > 2)
7630                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7631                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7632                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7633                                                           cfg->generic_sharing_context)) {
7634                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7635                                                 }
7636                                         } else {
7637                                                 if (cfg->verbose_level > 2)
7638                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7639
7640                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7641                                                         /* 
7642                                                          * This is needed since get_method_constrained can't find 
7643                                                          * the method in klass representing a type var.
7644                                                          * The type var is guaranteed to be a reference type in this
7645                                                          * case.
7646                                                          */
7647                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7648                                                                 g_assert (!cmethod->klass->valuetype);
7649                                                 } else {
7650                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7651                                                 }
7652                                         }
7653                                 }
7654                                         
7655                                 if (!cmethod || mono_loader_get_last_error ())
7656                                         LOAD_ERROR;
7657                                 if (!dont_verify && !cfg->skip_visibility) {
7658                                         MonoMethod *target_method = cil_method;
7659                                         if (method->is_inflated) {
7660                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7661                                         }
7662                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7663                                                 !mono_method_can_access_method (method, cil_method))
7664                                                 METHOD_ACCESS_FAILURE;
7665                                 }
7666
7667                                 if (mono_security_core_clr_enabled ())
7668                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7669
7670                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7671                                         /* MS.NET seems to silently convert this to a callvirt */
7672                                         virtual = 1;
7673
7674                                 {
7675                                         /*
7676                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7677                                          * converts to a callvirt.
7678                                          *
7679                                          * tests/bug-515884.il is an example of this behavior
7680                                          */
7681                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7682                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7683                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7684                                                 virtual = 1;
7685                                 }
7686
7687                                 if (!cmethod->klass->inited)
7688                                         if (!mono_class_init (cmethod->klass))
7689                                                 TYPE_LOAD_ERROR (cmethod->klass);
7690
7691                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7692                                     mini_class_is_system_array (cmethod->klass)) {
7693                                         array_rank = cmethod->klass->rank;
7694                                         fsig = mono_method_signature (cmethod);
7695                                 } else {
7696                                         fsig = mono_method_signature (cmethod);
7697
7698                                         if (!fsig)
7699                                                 LOAD_ERROR;
7700
7701                                         if (fsig->pinvoke) {
7702                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7703                                                         check_for_pending_exc, cfg->compile_aot);
7704                                                 fsig = mono_method_signature (wrapper);
7705                                         } else if (constrained_call) {
7706                                                 fsig = mono_method_signature (cmethod);
7707                                         } else {
7708                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7709                                         }
7710                                 }
7711
7712                                 mono_save_token_info (cfg, image, token, cil_method);
7713
7714                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7715                                         /*
7716                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7717                                          * foo (bar (), baz ())
7718                                          * works correctly. MS does this also:
7719                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7720                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7721                                          * even for simple cases, like:
7722                                          * int i = foo ();
7723                                          */
7724                                         /* Special case a few common successor opcodes */
7725                                         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)))
7726                                                 need_seq_point = TRUE;
7727                                 }
7728
7729                                 n = fsig->param_count + fsig->hasthis;
7730
7731                                 /* Don't support calls made using type arguments for now */
7732                                 /*
7733                                 if (cfg->gsharedvt) {
7734                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7735                                                 GSHAREDVT_FAILURE (*ip);
7736                                 }
7737                                 */
7738
7739                                 if (mono_security_cas_enabled ()) {
7740                                         if (check_linkdemand (cfg, method, cmethod))
7741                                                 INLINE_FAILURE ("linkdemand");
7742                                         CHECK_CFG_EXCEPTION;
7743                                 }
7744
7745                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7746                                         g_assert_not_reached ();
7747                         }
7748
7749                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7750                                 UNVERIFIED;
7751
7752                         if (!cfg->generic_sharing_context && cmethod)
7753                                 g_assert (!mono_method_check_context_used (cmethod));
7754
7755                         CHECK_STACK (n);
7756
7757                         //g_assert (!virtual || fsig->hasthis);
7758
7759                         sp -= n;
7760
7761                         if (constrained_call) {
7762                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7763                                         /*
7764                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7765                                          */
7766                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7767                                                 /* The 'Own method' case below */
7768                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7769                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7770                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7771                                                            (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)) &&
7772                                                            (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]))))) {
7773                                                 MonoInst *args [16];
7774
7775                                                 /*
7776                                                  * This case handles calls to
7777                                                  * - object:ToString()/Equals()/GetHashCode(),
7778                                                  * - System.IComparable<T>:CompareTo()
7779                                                  * - System.IEquatable<T>:Equals ()
7780                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7781                                                  */
7782
7783                                                 args [0] = sp [0];
7784                                                 if (mono_method_check_context_used (cmethod))
7785                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7786                                                 else
7787                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7788                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7789
7790                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7791                                                 if (fsig->hasthis && fsig->param_count) {
7792                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7793                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7794                                                         ins->dreg = alloc_preg (cfg);
7795                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7796                                                         MONO_ADD_INS (cfg->cbb, ins);
7797                                                         args [4] = ins;
7798
7799                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7800                                                                 int addr_reg;
7801
7802                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
7803
7804                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
7805                                                                 addr_reg = ins->dreg;
7806                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
7807                                                         } else {
7808                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
7809                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
7810                                                         }
7811                                                 } else {
7812                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
7813                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
7814                                                 }
7815                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
7816                                                 emit_widen = FALSE;
7817
7818                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
7819                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
7820                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
7821                                                         MonoInst *add;
7822
7823                                                         /* Unbox */
7824                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
7825                                                         MONO_ADD_INS (cfg->cbb, add);
7826                                                         /* Load value */
7827                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
7828                                                         MONO_ADD_INS (cfg->cbb, ins);
7829                                                         /* ins represents the call result */
7830                                                 }
7831
7832                                                 goto call_end;
7833                                         } else {
7834                                                 GSHAREDVT_FAILURE (*ip);
7835                                         }
7836                                 }
7837                                 /*
7838                                  * We have the `constrained.' prefix opcode.
7839                                  */
7840                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
7841                                         /*
7842                                          * The type parameter is instantiated as a valuetype,
7843                                          * but that type doesn't override the method we're
7844                                          * calling, so we need to box `this'.
7845                                          */
7846                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7847                                         ins->klass = constrained_call;
7848                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7849                                         CHECK_CFG_EXCEPTION;
7850                                 } else if (!constrained_call->valuetype) {
7851                                         int dreg = alloc_ireg_ref (cfg);
7852
7853                                         /*
7854                                          * The type parameter is instantiated as a reference
7855                                          * type.  We have a managed pointer on the stack, so
7856                                          * we need to dereference it here.
7857                                          */
7858                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
7859                                         ins->type = STACK_OBJ;
7860                                         sp [0] = ins;
7861                                 } else {
7862                                         if (cmethod->klass->valuetype) {
7863                                                 /* Own method */
7864                                         } else {
7865                                                 /* Interface method */
7866                                                 int ioffset, slot;
7867
7868                                                 mono_class_setup_vtable (constrained_call);
7869                                                 CHECK_TYPELOAD (constrained_call);
7870                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
7871                                                 if (ioffset == -1)
7872                                                         TYPE_LOAD_ERROR (constrained_call);
7873                                                 slot = mono_method_get_vtable_slot (cmethod);
7874                                                 if (slot == -1)
7875                                                         TYPE_LOAD_ERROR (cmethod->klass);
7876                                                 cmethod = constrained_call->vtable [ioffset + slot];
7877
7878                                                 if (cmethod->klass == mono_defaults.enum_class) {
7879                                                         /* Enum implements some interfaces, so treat this as the first case */
7880                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7881                                                         ins->klass = constrained_call;
7882                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7883                                                         CHECK_CFG_EXCEPTION;
7884                                                 }
7885                                         }
7886                                         virtual = 0;
7887                                 }
7888                                 constrained_call = NULL;
7889                         }
7890
7891                         if (!calli && check_call_signature (cfg, fsig, sp))
7892                                 UNVERIFIED;
7893
7894 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7895                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
7896                                 delegate_invoke = TRUE;
7897 #endif
7898
7899                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
7900                                 bblock = cfg->cbb;
7901                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7902                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7903                                         emit_widen = FALSE;
7904                                 }
7905
7906                                 goto call_end;
7907                         }
7908
7909                         /* 
7910                          * If the callee is a shared method, then its static cctor
7911                          * might not get called after the call was patched.
7912                          */
7913                         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)) {
7914                                 emit_generic_class_init (cfg, cmethod->klass);
7915                                 CHECK_TYPELOAD (cmethod->klass);
7916                         }
7917
7918                         if (cmethod)
7919                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
7920
7921                         if (cfg->generic_sharing_context && cmethod) {
7922                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
7923
7924                                 context_used = mini_method_check_context_used (cfg, cmethod);
7925
7926                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7927                                         /* Generic method interface
7928                                            calls are resolved via a
7929                                            helper function and don't
7930                                            need an imt. */
7931                                         if (!cmethod_context || !cmethod_context->method_inst)
7932                                                 pass_imt_from_rgctx = TRUE;
7933                                 }
7934
7935                                 /*
7936                                  * If a shared method calls another
7937                                  * shared method then the caller must
7938                                  * have a generic sharing context
7939                                  * because the magic trampoline
7940                                  * requires it.  FIXME: We shouldn't
7941                                  * have to force the vtable/mrgctx
7942                                  * variable here.  Instead there
7943                                  * should be a flag in the cfg to
7944                                  * request a generic sharing context.
7945                                  */
7946                                 if (context_used &&
7947                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
7948                                         mono_get_vtable_var (cfg);
7949                         }
7950
7951                         if (pass_vtable) {
7952                                 if (context_used) {
7953                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7954                                 } else {
7955                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7956
7957                                         CHECK_TYPELOAD (cmethod->klass);
7958                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7959                                 }
7960                         }
7961
7962                         if (pass_mrgctx) {
7963                                 g_assert (!vtable_arg);
7964
7965                                 if (!cfg->compile_aot) {
7966                                         /* 
7967                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
7968                                          * for type load errors before.
7969                                          */
7970                                         mono_class_setup_vtable (cmethod->klass);
7971                                         CHECK_TYPELOAD (cmethod->klass);
7972                                 }
7973
7974                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7975
7976                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
7977                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
7978                                          MONO_METHOD_IS_FINAL (cmethod)) &&
7979                                         !mono_class_is_marshalbyref (cmethod->klass)) {
7980                                         if (virtual)
7981                                                 check_this = TRUE;
7982                                         virtual = 0;
7983                                 }
7984                         }
7985
7986                         if (pass_imt_from_rgctx) {
7987                                 g_assert (!pass_vtable);
7988                                 g_assert (cmethod);
7989
7990                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
7991                                         cmethod, MONO_RGCTX_INFO_METHOD);
7992                         }
7993
7994                         if (check_this)
7995                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
7996
7997                         /* Calling virtual generic methods */
7998                         if (cmethod && virtual && 
7999                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8000                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8001                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8002                             fsig->generic_param_count && 
8003                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8004                                 MonoInst *this_temp, *this_arg_temp, *store;
8005                                 MonoInst *iargs [4];
8006                                 gboolean use_imt = FALSE;
8007
8008                                 g_assert (fsig->is_inflated);
8009
8010                                 /* Prevent inlining of methods that contain indirect calls */
8011                                 INLINE_FAILURE ("virtual generic call");
8012
8013                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8014                                         GSHAREDVT_FAILURE (*ip);
8015
8016 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8017                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8018                                         use_imt = TRUE;
8019 #endif
8020
8021                                 if (use_imt) {
8022                                         g_assert (!imt_arg);
8023                                         if (!context_used)
8024                                                 g_assert (cmethod->is_inflated);
8025                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8026                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8027                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8028                                 } else {
8029                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8030                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8031                                         MONO_ADD_INS (bblock, store);
8032
8033                                         /* FIXME: This should be a managed pointer */
8034                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8035
8036                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8037                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8038                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8039                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8040                                         addr = mono_emit_jit_icall (cfg,
8041                                                                                                 mono_helper_compile_generic_method, iargs);
8042
8043                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8044
8045                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8046                                 }
8047
8048                                 goto call_end;
8049                         }
8050
8051                         /*
8052                          * Implement a workaround for the inherent races involved in locking:
8053                          * Monitor.Enter ()
8054                          * try {
8055                          * } finally {
8056                          *    Monitor.Exit ()
8057                          * }
8058                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8059                          * try block, the Exit () won't be executed, see:
8060                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8061                          * To work around this, we extend such try blocks to include the last x bytes
8062                          * of the Monitor.Enter () call.
8063                          */
8064                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8065                                 MonoBasicBlock *tbb;
8066
8067                                 GET_BBLOCK (cfg, tbb, ip + 5);
8068                                 /* 
8069                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8070                                  * from Monitor.Enter like ArgumentNullException.
8071                                  */
8072                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8073                                         /* Mark this bblock as needing to be extended */
8074                                         tbb->extend_try_block = TRUE;
8075                                 }
8076                         }
8077
8078                         /* Conversion to a JIT intrinsic */
8079                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8080                                 bblock = cfg->cbb;
8081                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8082                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8083                                         emit_widen = FALSE;
8084                                 }
8085                                 goto call_end;
8086                         }
8087
8088                         /* Inlining */
8089                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8090                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8091                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8092                                  !g_list_find (dont_inline, cmethod)) {
8093                                 int costs;
8094                                 gboolean always = FALSE;
8095
8096                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8097                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8098                                         /* Prevent inlining of methods that call wrappers */
8099                                         INLINE_FAILURE ("wrapper call");
8100                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8101                                         always = TRUE;
8102                                 }
8103
8104                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
8105                                 if (costs) {
8106                                         cfg->real_offset += 5;
8107                                         bblock = cfg->cbb;
8108
8109                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8110                                                 /* *sp is already set by inline_method */
8111                                                 sp++;
8112                                                 push_res = FALSE;
8113                                         }
8114
8115                                         inline_costs += costs;
8116
8117                                         goto call_end;
8118                                 }
8119                         }
8120
8121                         /* Tail recursion elimination */
8122                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8123                                 gboolean has_vtargs = FALSE;
8124                                 int i;
8125
8126                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8127                                 INLINE_FAILURE ("tail call");
8128
8129                                 /* keep it simple */
8130                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8131                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8132                                                 has_vtargs = TRUE;
8133                                 }
8134
8135                                 if (!has_vtargs) {
8136                                         for (i = 0; i < n; ++i)
8137                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8138                                         MONO_INST_NEW (cfg, ins, OP_BR);
8139                                         MONO_ADD_INS (bblock, ins);
8140                                         tblock = start_bblock->out_bb [0];
8141                                         link_bblock (cfg, bblock, tblock);
8142                                         ins->inst_target_bb = tblock;
8143                                         start_new_bblock = 1;
8144
8145                                         /* skip the CEE_RET, too */
8146                                         if (ip_in_bb (cfg, bblock, ip + 5))
8147                                                 skip_ret = TRUE;
8148                                         push_res = FALSE;
8149                                         goto call_end;
8150                                 }
8151                         }
8152
8153                         inline_costs += 10 * num_calls++;
8154
8155                         /*
8156                          * Making generic calls out of gsharedvt methods.
8157                          */
8158                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8159                                 MonoRgctxInfoType info_type;
8160
8161                                 if (virtual) {
8162                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8163                                                 //GSHAREDVT_FAILURE (*ip);
8164                                         // disable for possible remoting calls
8165                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8166                                                 GSHAREDVT_FAILURE (*ip);
8167                                         if (fsig->generic_param_count) {
8168                                                 /* virtual generic call */
8169                                                 g_assert (mono_use_imt);
8170                                                 g_assert (!imt_arg);
8171                                                 /* Same as the virtual generic case above */
8172                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8173                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8174                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8175                                                 vtable_arg = NULL;
8176                                         }
8177                                 }
8178
8179                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8180                                         /* test_0_multi_dim_arrays () in gshared.cs */
8181                                         GSHAREDVT_FAILURE (*ip);
8182
8183                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8184                                         keep_this_alive = sp [0];
8185
8186                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8187                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8188                                 else
8189                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8190                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8191
8192                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8193                                 goto call_end;
8194                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8195                                 /*
8196                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8197                                  */
8198                                 MonoInst *callee = addr;
8199
8200                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8201                                         /* Not tested */
8202                                         GSHAREDVT_FAILURE (*ip);
8203
8204                                 addr = emit_get_rgctx_sig (cfg, context_used,
8205                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8206                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8207                                 goto call_end;
8208                         }
8209
8210                         /* Generic sharing */
8211                         /* FIXME: only do this for generic methods if
8212                            they are not shared! */
8213                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8214                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8215                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8216                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8217                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8218                                 INLINE_FAILURE ("gshared");
8219
8220                                 g_assert (cfg->generic_sharing_context && cmethod);
8221                                 g_assert (!addr);
8222
8223                                 /*
8224                                  * We are compiling a call to a
8225                                  * generic method from shared code,
8226                                  * which means that we have to look up
8227                                  * the method in the rgctx and do an
8228                                  * indirect call.
8229                                  */
8230                                 if (fsig->hasthis)
8231                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8232
8233                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8234                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8235                                 goto call_end;
8236                         }
8237
8238                         /* Indirect calls */
8239                         if (addr) {
8240                                 if (call_opcode == CEE_CALL)
8241                                         g_assert (context_used);
8242                                 else if (call_opcode == CEE_CALLI)
8243                                         g_assert (!vtable_arg);
8244                                 else
8245                                         /* FIXME: what the hell is this??? */
8246                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8247                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8248
8249                                 /* Prevent inlining of methods with indirect calls */
8250                                 INLINE_FAILURE ("indirect call");
8251
8252                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8253                                         int info_type;
8254                                         gpointer info_data;
8255
8256                                         /* 
8257                                          * Instead of emitting an indirect call, emit a direct call
8258                                          * with the contents of the aotconst as the patch info.
8259                                          */
8260                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8261                                                 info_type = addr->inst_c1;
8262                                                 info_data = addr->inst_p0;
8263                                         } else {
8264                                                 info_type = addr->inst_right->inst_c1;
8265                                                 info_data = addr->inst_right->inst_left;
8266                                         }
8267                                         
8268                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8269                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8270                                                 NULLIFY_INS (addr);
8271                                                 goto call_end;
8272                                         }
8273                                 }
8274                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8275                                 goto call_end;
8276                         }
8277                                         
8278                         /* Array methods */
8279                         if (array_rank) {
8280                                 MonoInst *addr;
8281
8282                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8283                                         MonoInst *val = sp [fsig->param_count];
8284
8285                                         if (val->type == STACK_OBJ) {
8286                                                 MonoInst *iargs [2];
8287
8288                                                 iargs [0] = sp [0];
8289                                                 iargs [1] = val;
8290                                                 
8291                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8292                                         }
8293                                         
8294                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8295                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8296                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8297                                                 emit_write_barrier (cfg, addr, val);
8298                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8299                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8300
8301                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8302                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8303                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8304                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8305                                         CHECK_TYPELOAD (cmethod->klass);
8306                                         
8307                                         readonly = FALSE;
8308                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8309                                         ins = addr;
8310                                 } else {
8311                                         g_assert_not_reached ();
8312                                 }
8313
8314                                 emit_widen = FALSE;
8315                                 goto call_end;
8316                         }
8317
8318                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8319                         if (ins)
8320                                 goto call_end;
8321
8322                         /* Tail prefix / tail call optimization */
8323
8324                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8325                         /* FIXME: runtime generic context pointer for jumps? */
8326                         /* FIXME: handle this for generic sharing eventually */
8327                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8328                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8329                                 supported_tail_call = TRUE;
8330
8331                         if (supported_tail_call) {
8332                                 MonoCallInst *call;
8333
8334                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8335                                 INLINE_FAILURE ("tail call");
8336
8337                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8338
8339                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8340                                         /* Handle tail calls similarly to normal calls */
8341                                         tail_call = TRUE;
8342                                 } else {
8343                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8344                                         call->tail_call = TRUE;
8345                                         call->method = cmethod;
8346                                         call->signature = mono_method_signature (cmethod);
8347
8348                                         /*
8349                                          * We implement tail calls by storing the actual arguments into the 
8350                                          * argument variables, then emitting a CEE_JMP.
8351                                          */
8352                                         for (i = 0; i < n; ++i) {
8353                                                 /* Prevent argument from being register allocated */
8354                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8355                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8356                                         }
8357                                         ins = (MonoInst*)call;
8358                                         ins->inst_p0 = cmethod;
8359                                         ins->inst_p1 = arg_array [0];
8360                                         MONO_ADD_INS (bblock, ins);
8361                                         link_bblock (cfg, bblock, end_bblock);                  
8362                                         start_new_bblock = 1;
8363
8364                                         // FIXME: Eliminate unreachable epilogs
8365
8366                                         /*
8367                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8368                                          * only reachable from this call.
8369                                          */
8370                                         GET_BBLOCK (cfg, tblock, ip + 5);
8371                                         if (tblock == bblock || tblock->in_count == 0)
8372                                                 skip_ret = TRUE;
8373                                         push_res = FALSE;
8374
8375                                         goto call_end;
8376                                 }
8377                         }
8378
8379                         /* 
8380                          * Synchronized wrappers.
8381                          * Its hard to determine where to replace a method with its synchronized
8382                          * wrapper without causing an infinite recursion. The current solution is
8383                          * to add the synchronized wrapper in the trampolines, and to
8384                          * change the called method to a dummy wrapper, and resolve that wrapper
8385                          * to the real method in mono_jit_compile_method ().
8386                          */
8387                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8388                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8389                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8390                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8391                         }
8392
8393                         /* Common call */
8394                         INLINE_FAILURE ("call");
8395                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8396                                                                                           imt_arg, vtable_arg);
8397
8398                         if (tail_call) {
8399                                 link_bblock (cfg, bblock, end_bblock);                  
8400                                 start_new_bblock = 1;
8401
8402                                 // FIXME: Eliminate unreachable epilogs
8403
8404                                 /*
8405                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8406                                  * only reachable from this call.
8407                                  */
8408                                 GET_BBLOCK (cfg, tblock, ip + 5);
8409                                 if (tblock == bblock || tblock->in_count == 0)
8410                                         skip_ret = TRUE;
8411                                 push_res = FALSE;
8412                         }
8413
8414                         call_end:
8415
8416                         /* End of call, INS should contain the result of the call, if any */
8417
8418                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8419                                 g_assert (ins);
8420                                 if (emit_widen)
8421                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8422                                 else
8423                                         *sp++ = ins;
8424                         }
8425
8426                         if (keep_this_alive) {
8427                                 MonoInst *dummy_use;
8428
8429                                 /* See mono_emit_method_call_full () */
8430                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8431                         }
8432
8433                         CHECK_CFG_EXCEPTION;
8434
8435                         ip += 5;
8436                         if (skip_ret) {
8437                                 g_assert (*ip == CEE_RET);
8438                                 ip += 1;
8439                         }
8440                         ins_flag = 0;
8441                         constrained_call = NULL;
8442                         if (need_seq_point)
8443                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8444                         break;
8445                 }
8446                 case CEE_RET:
8447                         if (cfg->method != method) {
8448                                 /* return from inlined method */
8449                                 /* 
8450                                  * If in_count == 0, that means the ret is unreachable due to
8451                                  * being preceeded by a throw. In that case, inline_method () will
8452                                  * handle setting the return value 
8453                                  * (test case: test_0_inline_throw ()).
8454                                  */
8455                                 if (return_var && cfg->cbb->in_count) {
8456                                         MonoType *ret_type = mono_method_signature (method)->ret;
8457
8458                                         MonoInst *store;
8459                                         CHECK_STACK (1);
8460                                         --sp;
8461
8462                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8463                                                 UNVERIFIED;
8464
8465                                         //g_assert (returnvar != -1);
8466                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8467                                         cfg->ret_var_set = TRUE;
8468                                 } 
8469                         } else {
8470                                 if (cfg->lmf_var && cfg->cbb->in_count)
8471                                         emit_pop_lmf (cfg);
8472
8473                                 if (cfg->ret) {
8474                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8475
8476                                         if (seq_points && !sym_seq_points) {
8477                                                 /* 
8478                                                  * Place a seq point here too even through the IL stack is not
8479                                                  * empty, so a step over on
8480                                                  * call <FOO>
8481                                                  * ret
8482                                                  * will work correctly.
8483                                                  */
8484                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8485                                                 MONO_ADD_INS (cfg->cbb, ins);
8486                                         }
8487
8488                                         g_assert (!return_var);
8489                                         CHECK_STACK (1);
8490                                         --sp;
8491
8492                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8493                                                 UNVERIFIED;
8494
8495                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8496                                                 MonoInst *ret_addr;
8497
8498                                                 if (!cfg->vret_addr) {
8499                                                         MonoInst *ins;
8500
8501                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8502                                                 } else {
8503                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8504
8505                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8506                                                         ins->klass = mono_class_from_mono_type (ret_type);
8507                                                 }
8508                                         } else {
8509 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8510                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8511                                                         MonoInst *iargs [1];
8512                                                         MonoInst *conv;
8513
8514                                                         iargs [0] = *sp;
8515                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8516                                                         mono_arch_emit_setret (cfg, method, conv);
8517                                                 } else {
8518                                                         mono_arch_emit_setret (cfg, method, *sp);
8519                                                 }
8520 #else
8521                                                 mono_arch_emit_setret (cfg, method, *sp);
8522 #endif
8523                                         }
8524                                 }
8525                         }
8526                         if (sp != stack_start)
8527                                 UNVERIFIED;
8528                         MONO_INST_NEW (cfg, ins, OP_BR);
8529                         ip++;
8530                         ins->inst_target_bb = end_bblock;
8531                         MONO_ADD_INS (bblock, ins);
8532                         link_bblock (cfg, bblock, end_bblock);
8533                         start_new_bblock = 1;
8534                         break;
8535                 case CEE_BR_S:
8536                         CHECK_OPSIZE (2);
8537                         MONO_INST_NEW (cfg, ins, OP_BR);
8538                         ip++;
8539                         target = ip + 1 + (signed char)(*ip);
8540                         ++ip;
8541                         GET_BBLOCK (cfg, tblock, target);
8542                         link_bblock (cfg, bblock, tblock);
8543                         ins->inst_target_bb = tblock;
8544                         if (sp != stack_start) {
8545                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8546                                 sp = stack_start;
8547                                 CHECK_UNVERIFIABLE (cfg);
8548                         }
8549                         MONO_ADD_INS (bblock, ins);
8550                         start_new_bblock = 1;
8551                         inline_costs += BRANCH_COST;
8552                         break;
8553                 case CEE_BEQ_S:
8554                 case CEE_BGE_S:
8555                 case CEE_BGT_S:
8556                 case CEE_BLE_S:
8557                 case CEE_BLT_S:
8558                 case CEE_BNE_UN_S:
8559                 case CEE_BGE_UN_S:
8560                 case CEE_BGT_UN_S:
8561                 case CEE_BLE_UN_S:
8562                 case CEE_BLT_UN_S:
8563                         CHECK_OPSIZE (2);
8564                         CHECK_STACK (2);
8565                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8566                         ip++;
8567                         target = ip + 1 + *(signed char*)ip;
8568                         ip++;
8569
8570                         ADD_BINCOND (NULL);
8571
8572                         sp = stack_start;
8573                         inline_costs += BRANCH_COST;
8574                         break;
8575                 case CEE_BR:
8576                         CHECK_OPSIZE (5);
8577                         MONO_INST_NEW (cfg, ins, OP_BR);
8578                         ip++;
8579
8580                         target = ip + 4 + (gint32)read32(ip);
8581                         ip += 4;
8582                         GET_BBLOCK (cfg, tblock, target);
8583                         link_bblock (cfg, bblock, tblock);
8584                         ins->inst_target_bb = tblock;
8585                         if (sp != stack_start) {
8586                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8587                                 sp = stack_start;
8588                                 CHECK_UNVERIFIABLE (cfg);
8589                         }
8590
8591                         MONO_ADD_INS (bblock, ins);
8592
8593                         start_new_bblock = 1;
8594                         inline_costs += BRANCH_COST;
8595                         break;
8596                 case CEE_BRFALSE_S:
8597                 case CEE_BRTRUE_S:
8598                 case CEE_BRFALSE:
8599                 case CEE_BRTRUE: {
8600                         MonoInst *cmp;
8601                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8602                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8603                         guint32 opsize = is_short ? 1 : 4;
8604
8605                         CHECK_OPSIZE (opsize);
8606                         CHECK_STACK (1);
8607                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8608                                 UNVERIFIED;
8609                         ip ++;
8610                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8611                         ip += opsize;
8612
8613                         sp--;
8614
8615                         GET_BBLOCK (cfg, tblock, target);
8616                         link_bblock (cfg, bblock, tblock);
8617                         GET_BBLOCK (cfg, tblock, ip);
8618                         link_bblock (cfg, bblock, tblock);
8619
8620                         if (sp != stack_start) {
8621                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8622                                 CHECK_UNVERIFIABLE (cfg);
8623                         }
8624
8625                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8626                         cmp->sreg1 = sp [0]->dreg;
8627                         type_from_op (cmp, sp [0], NULL);
8628                         CHECK_TYPE (cmp);
8629
8630 #if SIZEOF_REGISTER == 4
8631                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8632                                 /* Convert it to OP_LCOMPARE */
8633                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8634                                 ins->type = STACK_I8;
8635                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8636                                 ins->inst_l = 0;
8637                                 MONO_ADD_INS (bblock, ins);
8638                                 cmp->opcode = OP_LCOMPARE;
8639                                 cmp->sreg2 = ins->dreg;
8640                         }
8641 #endif
8642                         MONO_ADD_INS (bblock, cmp);
8643
8644                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8645                         type_from_op (ins, sp [0], NULL);
8646                         MONO_ADD_INS (bblock, ins);
8647                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8648                         GET_BBLOCK (cfg, tblock, target);
8649                         ins->inst_true_bb = tblock;
8650                         GET_BBLOCK (cfg, tblock, ip);
8651                         ins->inst_false_bb = tblock;
8652                         start_new_bblock = 2;
8653
8654                         sp = stack_start;
8655                         inline_costs += BRANCH_COST;
8656                         break;
8657                 }
8658                 case CEE_BEQ:
8659                 case CEE_BGE:
8660                 case CEE_BGT:
8661                 case CEE_BLE:
8662                 case CEE_BLT:
8663                 case CEE_BNE_UN:
8664                 case CEE_BGE_UN:
8665                 case CEE_BGT_UN:
8666                 case CEE_BLE_UN:
8667                 case CEE_BLT_UN:
8668                         CHECK_OPSIZE (5);
8669                         CHECK_STACK (2);
8670                         MONO_INST_NEW (cfg, ins, *ip);
8671                         ip++;
8672                         target = ip + 4 + (gint32)read32(ip);
8673                         ip += 4;
8674
8675                         ADD_BINCOND (NULL);
8676
8677                         sp = stack_start;
8678                         inline_costs += BRANCH_COST;
8679                         break;
8680                 case CEE_SWITCH: {
8681                         MonoInst *src1;
8682                         MonoBasicBlock **targets;
8683                         MonoBasicBlock *default_bblock;
8684                         MonoJumpInfoBBTable *table;
8685                         int offset_reg = alloc_preg (cfg);
8686                         int target_reg = alloc_preg (cfg);
8687                         int table_reg = alloc_preg (cfg);
8688                         int sum_reg = alloc_preg (cfg);
8689                         gboolean use_op_switch;
8690
8691                         CHECK_OPSIZE (5);
8692                         CHECK_STACK (1);
8693                         n = read32 (ip + 1);
8694                         --sp;
8695                         src1 = sp [0];
8696                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8697                                 UNVERIFIED;
8698
8699                         ip += 5;
8700                         CHECK_OPSIZE (n * sizeof (guint32));
8701                         target = ip + n * sizeof (guint32);
8702
8703                         GET_BBLOCK (cfg, default_bblock, target);
8704                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8705
8706                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8707                         for (i = 0; i < n; ++i) {
8708                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8709                                 targets [i] = tblock;
8710                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8711                                 ip += 4;
8712                         }
8713
8714                         if (sp != stack_start) {
8715                                 /* 
8716                                  * Link the current bb with the targets as well, so handle_stack_args
8717                                  * will set their in_stack correctly.
8718                                  */
8719                                 link_bblock (cfg, bblock, default_bblock);
8720                                 for (i = 0; i < n; ++i)
8721                                         link_bblock (cfg, bblock, targets [i]);
8722
8723                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8724                                 sp = stack_start;
8725                                 CHECK_UNVERIFIABLE (cfg);
8726                         }
8727
8728                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8729                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8730                         bblock = cfg->cbb;
8731
8732                         for (i = 0; i < n; ++i)
8733                                 link_bblock (cfg, bblock, targets [i]);
8734
8735                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8736                         table->table = targets;
8737                         table->table_size = n;
8738
8739                         use_op_switch = FALSE;
8740 #ifdef TARGET_ARM
8741                         /* ARM implements SWITCH statements differently */
8742                         /* FIXME: Make it use the generic implementation */
8743                         if (!cfg->compile_aot)
8744                                 use_op_switch = TRUE;
8745 #endif
8746
8747                         if (COMPILE_LLVM (cfg))
8748                                 use_op_switch = TRUE;
8749
8750                         cfg->cbb->has_jump_table = 1;
8751
8752                         if (use_op_switch) {
8753                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8754                                 ins->sreg1 = src1->dreg;
8755                                 ins->inst_p0 = table;
8756                                 ins->inst_many_bb = targets;
8757                                 ins->klass = GUINT_TO_POINTER (n);
8758                                 MONO_ADD_INS (cfg->cbb, ins);
8759                         } else {
8760                                 if (sizeof (gpointer) == 8)
8761                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8762                                 else
8763                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8764
8765 #if SIZEOF_REGISTER == 8
8766                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8767                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8768 #endif
8769
8770                                 if (cfg->compile_aot) {
8771                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8772                                 } else {
8773                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8774                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8775                                         ins->inst_p0 = table;
8776                                         ins->dreg = table_reg;
8777                                         MONO_ADD_INS (cfg->cbb, ins);
8778                                 }
8779
8780                                 /* FIXME: Use load_memindex */
8781                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8782                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8783                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8784                         }
8785                         start_new_bblock = 1;
8786                         inline_costs += (BRANCH_COST * 2);
8787                         break;
8788                 }
8789                 case CEE_LDIND_I1:
8790                 case CEE_LDIND_U1:
8791                 case CEE_LDIND_I2:
8792                 case CEE_LDIND_U2:
8793                 case CEE_LDIND_I4:
8794                 case CEE_LDIND_U4:
8795                 case CEE_LDIND_I8:
8796                 case CEE_LDIND_I:
8797                 case CEE_LDIND_R4:
8798                 case CEE_LDIND_R8:
8799                 case CEE_LDIND_REF:
8800                         CHECK_STACK (1);
8801                         --sp;
8802
8803                         switch (*ip) {
8804                         case CEE_LDIND_R4:
8805                         case CEE_LDIND_R8:
8806                                 dreg = alloc_freg (cfg);
8807                                 break;
8808                         case CEE_LDIND_I8:
8809                                 dreg = alloc_lreg (cfg);
8810                                 break;
8811                         case CEE_LDIND_REF:
8812                                 dreg = alloc_ireg_ref (cfg);
8813                                 break;
8814                         default:
8815                                 dreg = alloc_preg (cfg);
8816                         }
8817
8818                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
8819                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
8820                         ins->flags |= ins_flag;
8821                         ins_flag = 0;
8822                         MONO_ADD_INS (bblock, ins);
8823                         *sp++ = ins;
8824                         if (ins->flags & MONO_INST_VOLATILE) {
8825                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
8826                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8827                                 emit_memory_barrier (cfg, FullBarrier);
8828                         }
8829                         ++ip;
8830                         break;
8831                 case CEE_STIND_REF:
8832                 case CEE_STIND_I1:
8833                 case CEE_STIND_I2:
8834                 case CEE_STIND_I4:
8835                 case CEE_STIND_I8:
8836                 case CEE_STIND_R4:
8837                 case CEE_STIND_R8:
8838                 case CEE_STIND_I:
8839                         CHECK_STACK (2);
8840                         sp -= 2;
8841
8842                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
8843                         ins->flags |= ins_flag;
8844                         ins_flag = 0;
8845
8846                         if (ins->flags & MONO_INST_VOLATILE) {
8847                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
8848                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8849                                 emit_memory_barrier (cfg, FullBarrier);
8850                         }
8851
8852                         MONO_ADD_INS (bblock, ins);
8853
8854                         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)))
8855                                 emit_write_barrier (cfg, sp [0], sp [1]);
8856
8857                         inline_costs += 1;
8858                         ++ip;
8859                         break;
8860
8861                 case CEE_MUL:
8862                         CHECK_STACK (2);
8863
8864                         MONO_INST_NEW (cfg, ins, (*ip));
8865                         sp -= 2;
8866                         ins->sreg1 = sp [0]->dreg;
8867                         ins->sreg2 = sp [1]->dreg;
8868                         type_from_op (ins, sp [0], sp [1]);
8869                         CHECK_TYPE (ins);
8870                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8871
8872                         /* Use the immediate opcodes if possible */
8873                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
8874                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8875                                 if (imm_opcode != -1) {
8876                                         ins->opcode = imm_opcode;
8877                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
8878                                         ins->sreg2 = -1;
8879
8880                                         sp [1]->opcode = OP_NOP;
8881                                 }
8882                         }
8883
8884                         MONO_ADD_INS ((cfg)->cbb, (ins));
8885
8886                         *sp++ = mono_decompose_opcode (cfg, ins);
8887                         ip++;
8888                         break;
8889                 case CEE_ADD:
8890                 case CEE_SUB:
8891                 case CEE_DIV:
8892                 case CEE_DIV_UN:
8893                 case CEE_REM:
8894                 case CEE_REM_UN:
8895                 case CEE_AND:
8896                 case CEE_OR:
8897                 case CEE_XOR:
8898                 case CEE_SHL:
8899                 case CEE_SHR:
8900                 case CEE_SHR_UN:
8901                         CHECK_STACK (2);
8902
8903                         MONO_INST_NEW (cfg, ins, (*ip));
8904                         sp -= 2;
8905                         ins->sreg1 = sp [0]->dreg;
8906                         ins->sreg2 = sp [1]->dreg;
8907                         type_from_op (ins, sp [0], sp [1]);
8908                         CHECK_TYPE (ins);
8909                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
8910                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8911
8912                         /* FIXME: Pass opcode to is_inst_imm */
8913
8914                         /* Use the immediate opcodes if possible */
8915                         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)) {
8916                                 int imm_opcode;
8917
8918                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8919 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
8920                                 /* Keep emulated opcodes which are optimized away later */
8921                                 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) {
8922                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
8923                                 }
8924 #endif
8925                                 if (imm_opcode != -1) {
8926                                         ins->opcode = imm_opcode;
8927                                         if (sp [1]->opcode == OP_I8CONST) {
8928 #if SIZEOF_REGISTER == 8
8929                                                 ins->inst_imm = sp [1]->inst_l;
8930 #else
8931                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
8932                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
8933 #endif
8934                                         }
8935                                         else
8936                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
8937                                         ins->sreg2 = -1;
8938
8939                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
8940                                         if (sp [1]->next == NULL)
8941                                                 sp [1]->opcode = OP_NOP;
8942                                 }
8943                         }
8944                         MONO_ADD_INS ((cfg)->cbb, (ins));
8945
8946                         *sp++ = mono_decompose_opcode (cfg, ins);
8947                         ip++;
8948                         break;
8949                 case CEE_NEG:
8950                 case CEE_NOT:
8951                 case CEE_CONV_I1:
8952                 case CEE_CONV_I2:
8953                 case CEE_CONV_I4:
8954                 case CEE_CONV_R4:
8955                 case CEE_CONV_R8:
8956                 case CEE_CONV_U4:
8957                 case CEE_CONV_I8:
8958                 case CEE_CONV_U8:
8959                 case CEE_CONV_OVF_I8:
8960                 case CEE_CONV_OVF_U8:
8961                 case CEE_CONV_R_UN:
8962                         CHECK_STACK (1);
8963
8964                         /* Special case this earlier so we have long constants in the IR */
8965                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
8966                                 int data = sp [-1]->inst_c0;
8967                                 sp [-1]->opcode = OP_I8CONST;
8968                                 sp [-1]->type = STACK_I8;
8969 #if SIZEOF_REGISTER == 8
8970                                 if ((*ip) == CEE_CONV_U8)
8971                                         sp [-1]->inst_c0 = (guint32)data;
8972                                 else
8973                                         sp [-1]->inst_c0 = data;
8974 #else
8975                                 sp [-1]->inst_ls_word = data;
8976                                 if ((*ip) == CEE_CONV_U8)
8977                                         sp [-1]->inst_ms_word = 0;
8978                                 else
8979                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
8980 #endif
8981                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
8982                         }
8983                         else {
8984                                 ADD_UNOP (*ip);
8985                         }
8986                         ip++;
8987                         break;
8988                 case CEE_CONV_OVF_I4:
8989                 case CEE_CONV_OVF_I1:
8990                 case CEE_CONV_OVF_I2:
8991                 case CEE_CONV_OVF_I:
8992                 case CEE_CONV_OVF_U:
8993                         CHECK_STACK (1);
8994
8995                         if (sp [-1]->type == STACK_R8) {
8996                                 ADD_UNOP (CEE_CONV_OVF_I8);
8997                                 ADD_UNOP (*ip);
8998                         } else {
8999                                 ADD_UNOP (*ip);
9000                         }
9001                         ip++;
9002                         break;
9003                 case CEE_CONV_OVF_U1:
9004                 case CEE_CONV_OVF_U2:
9005                 case CEE_CONV_OVF_U4:
9006                         CHECK_STACK (1);
9007
9008                         if (sp [-1]->type == STACK_R8) {
9009                                 ADD_UNOP (CEE_CONV_OVF_U8);
9010                                 ADD_UNOP (*ip);
9011                         } else {
9012                                 ADD_UNOP (*ip);
9013                         }
9014                         ip++;
9015                         break;
9016                 case CEE_CONV_OVF_I1_UN:
9017                 case CEE_CONV_OVF_I2_UN:
9018                 case CEE_CONV_OVF_I4_UN:
9019                 case CEE_CONV_OVF_I8_UN:
9020                 case CEE_CONV_OVF_U1_UN:
9021                 case CEE_CONV_OVF_U2_UN:
9022                 case CEE_CONV_OVF_U4_UN:
9023                 case CEE_CONV_OVF_U8_UN:
9024                 case CEE_CONV_OVF_I_UN:
9025                 case CEE_CONV_OVF_U_UN:
9026                 case CEE_CONV_U2:
9027                 case CEE_CONV_U1:
9028                 case CEE_CONV_I:
9029                 case CEE_CONV_U:
9030                         CHECK_STACK (1);
9031                         ADD_UNOP (*ip);
9032                         CHECK_CFG_EXCEPTION;
9033                         ip++;
9034                         break;
9035                 case CEE_ADD_OVF:
9036                 case CEE_ADD_OVF_UN:
9037                 case CEE_MUL_OVF:
9038                 case CEE_MUL_OVF_UN:
9039                 case CEE_SUB_OVF:
9040                 case CEE_SUB_OVF_UN:
9041                         CHECK_STACK (2);
9042                         ADD_BINOP (*ip);
9043                         ip++;
9044                         break;
9045                 case CEE_CPOBJ:
9046                         GSHAREDVT_FAILURE (*ip);
9047                         CHECK_OPSIZE (5);
9048                         CHECK_STACK (2);
9049                         token = read32 (ip + 1);
9050                         klass = mini_get_class (method, token, generic_context);
9051                         CHECK_TYPELOAD (klass);
9052                         sp -= 2;
9053                         if (generic_class_is_reference_type (cfg, klass)) {
9054                                 MonoInst *store, *load;
9055                                 int dreg = alloc_ireg_ref (cfg);
9056
9057                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9058                                 load->flags |= ins_flag;
9059                                 MONO_ADD_INS (cfg->cbb, load);
9060
9061                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9062                                 store->flags |= ins_flag;
9063                                 MONO_ADD_INS (cfg->cbb, store);
9064
9065                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9066                                         emit_write_barrier (cfg, sp [0], sp [1]);
9067                         } else {
9068                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9069                         }
9070                         ins_flag = 0;
9071                         ip += 5;
9072                         break;
9073                 case CEE_LDOBJ: {
9074                         int loc_index = -1;
9075                         int stloc_len = 0;
9076
9077                         CHECK_OPSIZE (5);
9078                         CHECK_STACK (1);
9079                         --sp;
9080                         token = read32 (ip + 1);
9081                         klass = mini_get_class (method, token, generic_context);
9082                         CHECK_TYPELOAD (klass);
9083
9084                         /* Optimize the common ldobj+stloc combination */
9085                         switch (ip [5]) {
9086                         case CEE_STLOC_S:
9087                                 loc_index = ip [6];
9088                                 stloc_len = 2;
9089                                 break;
9090                         case CEE_STLOC_0:
9091                         case CEE_STLOC_1:
9092                         case CEE_STLOC_2:
9093                         case CEE_STLOC_3:
9094                                 loc_index = ip [5] - CEE_STLOC_0;
9095                                 stloc_len = 1;
9096                                 break;
9097                         default:
9098                                 break;
9099                         }
9100
9101                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9102                                 CHECK_LOCAL (loc_index);
9103
9104                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9105                                 ins->dreg = cfg->locals [loc_index]->dreg;
9106                                 ip += 5;
9107                                 ip += stloc_len;
9108                                 break;
9109                         }
9110
9111                         /* Optimize the ldobj+stobj combination */
9112                         /* The reference case ends up being a load+store anyway */
9113                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9114                                 CHECK_STACK (1);
9115
9116                                 sp --;
9117
9118                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9119
9120                                 ip += 5 + 5;
9121                                 ins_flag = 0;
9122                                 break;
9123                         }
9124
9125                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9126                         *sp++ = ins;
9127
9128                         ip += 5;
9129                         ins_flag = 0;
9130                         inline_costs += 1;
9131                         break;
9132                 }
9133                 case CEE_LDSTR:
9134                         CHECK_STACK_OVF (1);
9135                         CHECK_OPSIZE (5);
9136                         n = read32 (ip + 1);
9137
9138                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9139                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9140                                 ins->type = STACK_OBJ;
9141                                 *sp = ins;
9142                         }
9143                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9144                                 MonoInst *iargs [1];
9145
9146                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9147                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9148                         } else {
9149                                 if (cfg->opt & MONO_OPT_SHARED) {
9150                                         MonoInst *iargs [3];
9151
9152                                         if (cfg->compile_aot) {
9153                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9154                                         }
9155                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9156                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9157                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9158                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9159                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9160                                 } else {
9161                                         if (bblock->out_of_line) {
9162                                                 MonoInst *iargs [2];
9163
9164                                                 if (image == mono_defaults.corlib) {
9165                                                         /* 
9166                                                          * Avoid relocations in AOT and save some space by using a 
9167                                                          * version of helper_ldstr specialized to mscorlib.
9168                                                          */
9169                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9170                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9171                                                 } else {
9172                                                         /* Avoid creating the string object */
9173                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9174                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9175                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9176                                                 }
9177                                         } 
9178                                         else
9179                                         if (cfg->compile_aot) {
9180                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9181                                                 *sp = ins;
9182                                                 MONO_ADD_INS (bblock, ins);
9183                                         } 
9184                                         else {
9185                                                 NEW_PCONST (cfg, ins, NULL);
9186                                                 ins->type = STACK_OBJ;
9187                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9188                                                 if (!ins->inst_p0)
9189                                                         OUT_OF_MEMORY_FAILURE;
9190
9191                                                 *sp = ins;
9192                                                 MONO_ADD_INS (bblock, ins);
9193                                         }
9194                                 }
9195                         }
9196
9197                         sp++;
9198                         ip += 5;
9199                         break;
9200                 case CEE_NEWOBJ: {
9201                         MonoInst *iargs [2];
9202                         MonoMethodSignature *fsig;
9203                         MonoInst this_ins;
9204                         MonoInst *alloc;
9205                         MonoInst *vtable_arg = NULL;
9206
9207                         CHECK_OPSIZE (5);
9208                         token = read32 (ip + 1);
9209                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9210                         if (!cmethod || mono_loader_get_last_error ())
9211                                 LOAD_ERROR;
9212                         fsig = mono_method_get_signature (cmethod, image, token);
9213                         if (!fsig)
9214                                 LOAD_ERROR;
9215
9216                         mono_save_token_info (cfg, image, token, cmethod);
9217
9218                         if (!mono_class_init (cmethod->klass))
9219                                 TYPE_LOAD_ERROR (cmethod->klass);
9220
9221                         context_used = mini_method_check_context_used (cfg, cmethod);
9222
9223                         if (mono_security_cas_enabled ()) {
9224                                 if (check_linkdemand (cfg, method, cmethod))
9225                                         INLINE_FAILURE ("linkdemand");
9226                                 CHECK_CFG_EXCEPTION;
9227                         } else if (mono_security_core_clr_enabled ()) {
9228                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9229                         }
9230
9231                         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)) {
9232                                 emit_generic_class_init (cfg, cmethod->klass);
9233                                 CHECK_TYPELOAD (cmethod->klass);
9234                         }
9235
9236                         /*
9237                         if (cfg->gsharedvt) {
9238                                 if (mini_is_gsharedvt_variable_signature (sig))
9239                                         GSHAREDVT_FAILURE (*ip);
9240                         }
9241                         */
9242
9243                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9244                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9245                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9246                                         mono_class_vtable (cfg->domain, cmethod->klass);
9247                                         CHECK_TYPELOAD (cmethod->klass);
9248
9249                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9250                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9251                                 } else {
9252                                         if (context_used) {
9253                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9254                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9255                                         } else {
9256                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9257
9258                                                 CHECK_TYPELOAD (cmethod->klass);
9259                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9260                                         }
9261                                 }
9262                         }
9263
9264                         n = fsig->param_count;
9265                         CHECK_STACK (n);
9266
9267                         /* 
9268                          * Generate smaller code for the common newobj <exception> instruction in
9269                          * argument checking code.
9270                          */
9271                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9272                                 is_exception_class (cmethod->klass) && n <= 2 &&
9273                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9274                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9275                                 MonoInst *iargs [3];
9276
9277                                 g_assert (!vtable_arg);
9278
9279                                 sp -= n;
9280
9281                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9282                                 switch (n) {
9283                                 case 0:
9284                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9285                                         break;
9286                                 case 1:
9287                                         iargs [1] = sp [0];
9288                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9289                                         break;
9290                                 case 2:
9291                                         iargs [1] = sp [0];
9292                                         iargs [2] = sp [1];
9293                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9294                                         break;
9295                                 default:
9296                                         g_assert_not_reached ();
9297                                 }
9298
9299                                 ip += 5;
9300                                 inline_costs += 5;
9301                                 break;
9302                         }
9303
9304                         /* move the args to allow room for 'this' in the first position */
9305                         while (n--) {
9306                                 --sp;
9307                                 sp [1] = sp [0];
9308                         }
9309
9310                         /* check_call_signature () requires sp[0] to be set */
9311                         this_ins.type = STACK_OBJ;
9312                         sp [0] = &this_ins;
9313                         if (check_call_signature (cfg, fsig, sp))
9314                                 UNVERIFIED;
9315
9316                         iargs [0] = NULL;
9317
9318                         if (mini_class_is_system_array (cmethod->klass)) {
9319                                 g_assert (!vtable_arg);
9320
9321                                 *sp = emit_get_rgctx_method (cfg, context_used,
9322                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9323
9324                                 /* Avoid varargs in the common case */
9325                                 if (fsig->param_count == 1)
9326                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9327                                 else if (fsig->param_count == 2)
9328                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9329                                 else if (fsig->param_count == 3)
9330                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9331                                 else if (fsig->param_count == 4)
9332                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9333                                 else
9334                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9335                         } else if (cmethod->string_ctor) {
9336                                 g_assert (!context_used);
9337                                 g_assert (!vtable_arg);
9338                                 /* we simply pass a null pointer */
9339                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9340                                 /* now call the string ctor */
9341                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9342                         } else {
9343                                 MonoInst* callvirt_this_arg = NULL;
9344                                 
9345                                 if (cmethod->klass->valuetype) {
9346                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9347                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9348                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9349
9350                                         alloc = NULL;
9351
9352                                         /* 
9353                                          * The code generated by mini_emit_virtual_call () expects
9354                                          * iargs [0] to be a boxed instance, but luckily the vcall
9355                                          * will be transformed into a normal call there.
9356                                          */
9357                                 } else if (context_used) {
9358                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9359                                         *sp = alloc;
9360                                 } else {
9361                                         MonoVTable *vtable = NULL;
9362
9363                                         if (!cfg->compile_aot)
9364                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9365                                         CHECK_TYPELOAD (cmethod->klass);
9366
9367                                         /*
9368                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9369                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9370                                          * As a workaround, we call class cctors before allocating objects.
9371                                          */
9372                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9373                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9374                                                 if (cfg->verbose_level > 2)
9375                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9376                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9377                                         }
9378
9379                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9380                                         *sp = alloc;
9381                                 }
9382                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9383
9384                                 if (alloc)
9385                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9386
9387                                 /* Now call the actual ctor */
9388                                 /* Avoid virtual calls to ctors if possible */
9389                                 if (mono_class_is_marshalbyref (cmethod->klass))
9390                                         callvirt_this_arg = sp [0];
9391
9392
9393                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9394                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9395                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9396                                                 *sp = ins;
9397                                                 sp++;
9398                                         }
9399
9400                                         CHECK_CFG_EXCEPTION;
9401                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9402                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9403                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9404                                     !g_list_find (dont_inline, cmethod)) {
9405                                         int costs;
9406
9407                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9408                                                 cfg->real_offset += 5;
9409                                                 bblock = cfg->cbb;
9410
9411                                                 inline_costs += costs - 5;
9412                                         } else {
9413                                                 INLINE_FAILURE ("inline failure");
9414                                                 // FIXME-VT: Clean this up
9415                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9416                                                         GSHAREDVT_FAILURE(*ip);
9417                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9418                                         }
9419                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9420                                         MonoInst *addr;
9421
9422                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9423                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9424                                 } else if (context_used &&
9425                                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
9426                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
9427                                         MonoInst *cmethod_addr;
9428
9429                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9430                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9431
9432                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9433                                 } else {
9434                                         INLINE_FAILURE ("ctor call");
9435                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9436                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9437                                 }
9438                         }
9439
9440                         if (alloc == NULL) {
9441                                 /* Valuetype */
9442                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9443                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9444                                 *sp++= ins;
9445                         }
9446                         else
9447                                 *sp++ = alloc;
9448                         
9449                         ip += 5;
9450                         inline_costs += 5;
9451                         break;
9452                 }
9453                 case CEE_CASTCLASS:
9454                         CHECK_STACK (1);
9455                         --sp;
9456                         CHECK_OPSIZE (5);
9457                         token = read32 (ip + 1);
9458                         klass = mini_get_class (method, token, generic_context);
9459                         CHECK_TYPELOAD (klass);
9460                         if (sp [0]->type != STACK_OBJ)
9461                                 UNVERIFIED;
9462
9463                         context_used = mini_class_check_context_used (cfg, klass);
9464
9465                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9466                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9467                                 MonoInst *args [3];
9468
9469                                 /* obj */
9470                                 args [0] = *sp;
9471
9472                                 /* klass */
9473                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9474
9475                                 /* inline cache*/
9476                                 if (cfg->compile_aot)
9477                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9478                                 else
9479                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9480
9481                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9482
9483                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9484                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9485                                 reset_cast_details (cfg);
9486                                 ip += 5;
9487                                 inline_costs += 2;
9488                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9489                                 MonoMethod *mono_castclass;
9490                                 MonoInst *iargs [1];
9491                                 int costs;
9492
9493                                 mono_castclass = mono_marshal_get_castclass (klass); 
9494                                 iargs [0] = sp [0];
9495                                 
9496                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9497                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9498                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9499                                 reset_cast_details (cfg);
9500                                 CHECK_CFG_EXCEPTION;
9501                                 g_assert (costs > 0);
9502                                 
9503                                 ip += 5;
9504                                 cfg->real_offset += 5;
9505                                 bblock = cfg->cbb;
9506
9507                                 *sp++ = iargs [0];
9508
9509                                 inline_costs += costs;
9510                         }
9511                         else {
9512                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9513                                 CHECK_CFG_EXCEPTION;
9514                                 bblock = cfg->cbb;
9515                                 *sp ++ = ins;
9516                                 ip += 5;
9517                         }
9518                         break;
9519                 case CEE_ISINST: {
9520                         CHECK_STACK (1);
9521                         --sp;
9522                         CHECK_OPSIZE (5);
9523                         token = read32 (ip + 1);
9524                         klass = mini_get_class (method, token, generic_context);
9525                         CHECK_TYPELOAD (klass);
9526                         if (sp [0]->type != STACK_OBJ)
9527                                 UNVERIFIED;
9528  
9529                         context_used = mini_class_check_context_used (cfg, klass);
9530
9531                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9532                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9533                                 MonoInst *args [3];
9534
9535                                 /* obj */
9536                                 args [0] = *sp;
9537
9538                                 /* klass */
9539                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9540
9541                                 /* inline cache*/
9542                                 if (cfg->compile_aot)
9543                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9544                                 else
9545                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9546
9547                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9548                                 ip += 5;
9549                                 inline_costs += 2;
9550                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9551                                 MonoMethod *mono_isinst;
9552                                 MonoInst *iargs [1];
9553                                 int costs;
9554
9555                                 mono_isinst = mono_marshal_get_isinst (klass); 
9556                                 iargs [0] = sp [0];
9557
9558                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9559                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9560                                 CHECK_CFG_EXCEPTION;
9561                                 g_assert (costs > 0);
9562                                 
9563                                 ip += 5;
9564                                 cfg->real_offset += 5;
9565                                 bblock = cfg->cbb;
9566
9567                                 *sp++= iargs [0];
9568
9569                                 inline_costs += costs;
9570                         }
9571                         else {
9572                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9573                                 CHECK_CFG_EXCEPTION;
9574                                 bblock = cfg->cbb;
9575                                 *sp ++ = ins;
9576                                 ip += 5;
9577                         }
9578                         break;
9579                 }
9580                 case CEE_UNBOX_ANY: {
9581                         CHECK_STACK (1);
9582                         --sp;
9583                         CHECK_OPSIZE (5);
9584                         token = read32 (ip + 1);
9585                         klass = mini_get_class (method, token, generic_context);
9586                         CHECK_TYPELOAD (klass);
9587  
9588                         mono_save_token_info (cfg, image, token, klass);
9589
9590                         context_used = mini_class_check_context_used (cfg, klass);
9591
9592                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9593                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9594                                 sp ++;
9595
9596                                 ip += 5;
9597                                 inline_costs += 2;
9598                                 break;
9599                         }
9600
9601                         if (generic_class_is_reference_type (cfg, klass)) {
9602                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9603                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9604                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9605                                         MonoInst *args [3];
9606
9607                                         /* obj */
9608                                         args [0] = *sp;
9609
9610                                         /* klass */
9611                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9612
9613                                         /* inline cache*/
9614                                         /*FIXME AOT support*/
9615                                         if (cfg->compile_aot)
9616                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9617                                         else
9618                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9619
9620                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9621                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9622                                         ip += 5;
9623                                         inline_costs += 2;
9624                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9625                                         MonoMethod *mono_castclass;
9626                                         MonoInst *iargs [1];
9627                                         int costs;
9628
9629                                         mono_castclass = mono_marshal_get_castclass (klass); 
9630                                         iargs [0] = sp [0];
9631
9632                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9633                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9634                                         CHECK_CFG_EXCEPTION;
9635                                         g_assert (costs > 0);
9636                                 
9637                                         ip += 5;
9638                                         cfg->real_offset += 5;
9639                                         bblock = cfg->cbb;
9640
9641                                         *sp++ = iargs [0];
9642                                         inline_costs += costs;
9643                                 } else {
9644                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9645                                         CHECK_CFG_EXCEPTION;
9646                                         bblock = cfg->cbb;
9647                                         *sp ++ = ins;
9648                                         ip += 5;
9649                                 }
9650                                 break;
9651                         }
9652
9653                         if (mono_class_is_nullable (klass)) {
9654                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9655                                 *sp++= ins;
9656                                 ip += 5;
9657                                 break;
9658                         }
9659
9660                         /* UNBOX */
9661                         ins = handle_unbox (cfg, klass, sp, context_used);
9662                         *sp = ins;
9663
9664                         ip += 5;
9665
9666                         /* LDOBJ */
9667                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9668                         *sp++ = ins;
9669
9670                         inline_costs += 2;
9671                         break;
9672                 }
9673                 case CEE_BOX: {
9674                         MonoInst *val;
9675
9676                         CHECK_STACK (1);
9677                         --sp;
9678                         val = *sp;
9679                         CHECK_OPSIZE (5);
9680                         token = read32 (ip + 1);
9681                         klass = mini_get_class (method, token, generic_context);
9682                         CHECK_TYPELOAD (klass);
9683
9684                         mono_save_token_info (cfg, image, token, klass);
9685
9686                         context_used = mini_class_check_context_used (cfg, klass);
9687
9688                         if (generic_class_is_reference_type (cfg, klass)) {
9689                                 *sp++ = val;
9690                                 ip += 5;
9691                                 break;
9692                         }
9693
9694                         if (klass == mono_defaults.void_class)
9695                                 UNVERIFIED;
9696                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9697                                 UNVERIFIED;
9698                         /* frequent check in generic code: box (struct), brtrue */
9699
9700                         // FIXME: LLVM can't handle the inconsistent bb linking
9701                         if (!mono_class_is_nullable (klass) &&
9702                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9703                                 (ip [5] == CEE_BRTRUE || 
9704                                  ip [5] == CEE_BRTRUE_S ||
9705                                  ip [5] == CEE_BRFALSE ||
9706                                  ip [5] == CEE_BRFALSE_S)) {
9707                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9708                                 int dreg;
9709                                 MonoBasicBlock *true_bb, *false_bb;
9710
9711                                 ip += 5;
9712
9713                                 if (cfg->verbose_level > 3) {
9714                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9715                                         printf ("<box+brtrue opt>\n");
9716                                 }
9717
9718                                 switch (*ip) {
9719                                 case CEE_BRTRUE_S:
9720                                 case CEE_BRFALSE_S:
9721                                         CHECK_OPSIZE (2);
9722                                         ip++;
9723                                         target = ip + 1 + (signed char)(*ip);
9724                                         ip++;
9725                                         break;
9726                                 case CEE_BRTRUE:
9727                                 case CEE_BRFALSE:
9728                                         CHECK_OPSIZE (5);
9729                                         ip++;
9730                                         target = ip + 4 + (gint)(read32 (ip));
9731                                         ip += 4;
9732                                         break;
9733                                 default:
9734                                         g_assert_not_reached ();
9735                                 }
9736
9737                                 /* 
9738                                  * We need to link both bblocks, since it is needed for handling stack
9739                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9740                                  * Branching to only one of them would lead to inconsistencies, so
9741                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9742                                  */
9743                                 GET_BBLOCK (cfg, true_bb, target);
9744                                 GET_BBLOCK (cfg, false_bb, ip);
9745
9746                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9747                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9748
9749                                 if (sp != stack_start) {
9750                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9751                                         sp = stack_start;
9752                                         CHECK_UNVERIFIABLE (cfg);
9753                                 }
9754
9755                                 if (COMPILE_LLVM (cfg)) {
9756                                         dreg = alloc_ireg (cfg);
9757                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9758                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9759
9760                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9761                                 } else {
9762                                         /* The JIT can't eliminate the iconst+compare */
9763                                         MONO_INST_NEW (cfg, ins, OP_BR);
9764                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9765                                         MONO_ADD_INS (cfg->cbb, ins);
9766                                 }
9767
9768                                 start_new_bblock = 1;
9769                                 break;
9770                         }
9771
9772                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9773
9774                         CHECK_CFG_EXCEPTION;
9775                         ip += 5;
9776                         inline_costs += 1;
9777                         break;
9778                 }
9779                 case CEE_UNBOX: {
9780                         CHECK_STACK (1);
9781                         --sp;
9782                         CHECK_OPSIZE (5);
9783                         token = read32 (ip + 1);
9784                         klass = mini_get_class (method, token, generic_context);
9785                         CHECK_TYPELOAD (klass);
9786
9787                         mono_save_token_info (cfg, image, token, klass);
9788
9789                         context_used = mini_class_check_context_used (cfg, klass);
9790
9791                         if (mono_class_is_nullable (klass)) {
9792                                 MonoInst *val;
9793
9794                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9795                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9796
9797                                 *sp++= ins;
9798                         } else {
9799                                 ins = handle_unbox (cfg, klass, sp, context_used);
9800                                 *sp++ = ins;
9801                         }
9802                         ip += 5;
9803                         inline_costs += 2;
9804                         break;
9805                 }
9806                 case CEE_LDFLD:
9807                 case CEE_LDFLDA:
9808                 case CEE_STFLD:
9809                 case CEE_LDSFLD:
9810                 case CEE_LDSFLDA:
9811                 case CEE_STSFLD: {
9812                         MonoClassField *field;
9813 #ifndef DISABLE_REMOTING
9814                         int costs;
9815 #endif
9816                         guint foffset;
9817                         gboolean is_instance;
9818                         int op;
9819                         gpointer addr = NULL;
9820                         gboolean is_special_static;
9821                         MonoType *ftype;
9822                         MonoInst *store_val = NULL;
9823                         MonoInst *thread_ins;
9824
9825                         op = *ip;
9826                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
9827                         if (is_instance) {
9828                                 if (op == CEE_STFLD) {
9829                                         CHECK_STACK (2);
9830                                         sp -= 2;
9831                                         store_val = sp [1];
9832                                 } else {
9833                                         CHECK_STACK (1);
9834                                         --sp;
9835                                 }
9836                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
9837                                         UNVERIFIED;
9838                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
9839                                         UNVERIFIED;
9840                         } else {
9841                                 if (op == CEE_STSFLD) {
9842                                         CHECK_STACK (1);
9843                                         sp--;
9844                                         store_val = sp [0];
9845                                 }
9846                         }
9847
9848                         CHECK_OPSIZE (5);
9849                         token = read32 (ip + 1);
9850                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
9851                                 field = mono_method_get_wrapper_data (method, token);
9852                                 klass = field->parent;
9853                         }
9854                         else {
9855                                 field = mono_field_from_token (image, token, &klass, generic_context);
9856                         }
9857                         if (!field)
9858                                 LOAD_ERROR;
9859                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
9860                                 FIELD_ACCESS_FAILURE;
9861                         mono_class_init (klass);
9862
9863                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
9864                                 UNVERIFIED;
9865
9866                         /* if the class is Critical then transparent code cannot access it's fields */
9867                         if (!is_instance && mono_security_core_clr_enabled ())
9868                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9869
9870                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
9871                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
9872                         if (mono_security_core_clr_enabled ())
9873                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9874                         */
9875
9876                         /*
9877                          * LDFLD etc. is usable on static fields as well, so convert those cases to
9878                          * the static case.
9879                          */
9880                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9881                                 switch (op) {
9882                                 case CEE_LDFLD:
9883                                         op = CEE_LDSFLD;
9884                                         break;
9885                                 case CEE_STFLD:
9886                                         op = CEE_STSFLD;
9887                                         break;
9888                                 case CEE_LDFLDA:
9889                                         op = CEE_LDSFLDA;
9890                                         break;
9891                                 default:
9892                                         g_assert_not_reached ();
9893                                 }
9894                                 is_instance = FALSE;
9895                         }
9896
9897                         context_used = mini_class_check_context_used (cfg, klass);
9898
9899                         /* INSTANCE CASE */
9900
9901                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
9902                         if (op == CEE_STFLD) {
9903                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
9904                                         UNVERIFIED;
9905 #ifndef DISABLE_REMOTING
9906                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
9907                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
9908                                         MonoInst *iargs [5];
9909
9910                                         GSHAREDVT_FAILURE (op);
9911
9912                                         iargs [0] = sp [0];
9913                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9914                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9915                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
9916                                                     field->offset);
9917                                         iargs [4] = sp [1];
9918
9919                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9920                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
9921                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
9922                                                 CHECK_CFG_EXCEPTION;
9923                                                 g_assert (costs > 0);
9924                                                       
9925                                                 cfg->real_offset += 5;
9926                                                 bblock = cfg->cbb;
9927
9928                                                 inline_costs += costs;
9929                                         } else {
9930                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
9931                                         }
9932                                 } else
9933 #endif
9934                                 {
9935                                         MonoInst *store;
9936
9937                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9938
9939                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9940                                                 MonoInst *offset_ins;
9941
9942                                                 context_used = mini_class_check_context_used (cfg, klass);
9943
9944                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9945                                                 dreg = alloc_ireg_mp (cfg);
9946                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9947                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
9948                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
9949                                         } else {
9950                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
9951                                         }
9952                                         if (sp [0]->opcode != OP_LDADDR)
9953                                                 store->flags |= MONO_INST_FAULT;
9954
9955                                 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)) {
9956                                         /* insert call to write barrier */
9957                                         MonoInst *ptr;
9958                                         int dreg;
9959
9960                                         dreg = alloc_ireg_mp (cfg);
9961                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
9962                                         emit_write_barrier (cfg, ptr, sp [1]);
9963                                 }
9964
9965                                         store->flags |= ins_flag;
9966                                 }
9967                                 ins_flag = 0;
9968                                 ip += 5;
9969                                 break;
9970                         }
9971
9972 #ifndef DISABLE_REMOTING
9973                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
9974                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
9975                                 MonoInst *iargs [4];
9976
9977                                 GSHAREDVT_FAILURE (op);
9978
9979                                 iargs [0] = sp [0];
9980                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9981                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9982                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
9983                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9984                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
9985                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9986                                         CHECK_CFG_EXCEPTION;
9987                                         bblock = cfg->cbb;
9988                                         g_assert (costs > 0);
9989                                                       
9990                                         cfg->real_offset += 5;
9991
9992                                         *sp++ = iargs [0];
9993
9994                                         inline_costs += costs;
9995                                 } else {
9996                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
9997                                         *sp++ = ins;
9998                                 }
9999                         } else 
10000 #endif
10001                         if (is_instance) {
10002                                 if (sp [0]->type == STACK_VTYPE) {
10003                                         MonoInst *var;
10004
10005                                         /* Have to compute the address of the variable */
10006
10007                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10008                                         if (!var)
10009                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10010                                         else
10011                                                 g_assert (var->klass == klass);
10012                                         
10013                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10014                                         sp [0] = ins;
10015                                 }
10016
10017                                 if (op == CEE_LDFLDA) {
10018                                         if (is_magic_tls_access (field)) {
10019                                                 GSHAREDVT_FAILURE (*ip);
10020                                                 ins = sp [0];
10021                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10022                                         } else {
10023                                                 if (sp [0]->type == STACK_OBJ) {
10024                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10025                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10026                                                 }
10027
10028                                                 dreg = alloc_ireg_mp (cfg);
10029
10030                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10031                                                         MonoInst *offset_ins;
10032
10033                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10034                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10035                                                 } else {
10036                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10037                                                 }
10038                                                 ins->klass = mono_class_from_mono_type (field->type);
10039                                                 ins->type = STACK_MP;
10040                                                 *sp++ = ins;
10041                                         }
10042                                 } else {
10043                                         MonoInst *load;
10044
10045                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10046
10047                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10048                                                 MonoInst *offset_ins;
10049
10050                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10051                                                 dreg = alloc_ireg_mp (cfg);
10052                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10053                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10054                                         } else {
10055                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10056                                         }
10057                                         load->flags |= ins_flag;
10058                                         if (sp [0]->opcode != OP_LDADDR)
10059                                                 load->flags |= MONO_INST_FAULT;
10060                                         *sp++ = load;
10061                                 }
10062                         }
10063
10064                         if (is_instance) {
10065                                 ins_flag = 0;
10066                                 ip += 5;
10067                                 break;
10068                         }
10069
10070                         /* STATIC CASE */
10071
10072                         /*
10073                          * We can only support shared generic static
10074                          * field access on architectures where the
10075                          * trampoline code has been extended to handle
10076                          * the generic class init.
10077                          */
10078 #ifndef MONO_ARCH_VTABLE_REG
10079                         GENERIC_SHARING_FAILURE (op);
10080 #endif
10081
10082                         context_used = mini_class_check_context_used (cfg, klass);
10083
10084                         ftype = mono_field_get_type (field);
10085
10086                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10087                                 UNVERIFIED;
10088
10089                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10090                          * to be called here.
10091                          */
10092                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10093                                 mono_class_vtable (cfg->domain, klass);
10094                                 CHECK_TYPELOAD (klass);
10095                         }
10096                         mono_domain_lock (cfg->domain);
10097                         if (cfg->domain->special_static_fields)
10098                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10099                         mono_domain_unlock (cfg->domain);
10100
10101                         is_special_static = mono_class_field_is_special_static (field);
10102
10103                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10104                                 thread_ins = mono_get_thread_intrinsic (cfg);
10105                         else
10106                                 thread_ins = NULL;
10107
10108                         /* Generate IR to compute the field address */
10109                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10110                                 /*
10111                                  * Fast access to TLS data
10112                                  * Inline version of get_thread_static_data () in
10113                                  * threads.c.
10114                                  */
10115                                 guint32 offset;
10116                                 int idx, static_data_reg, array_reg, dreg;
10117
10118                                 GSHAREDVT_FAILURE (op);
10119
10120                                 // offset &= 0x7fffffff;
10121                                 // idx = (offset >> 24) - 1;
10122                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10123                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10124                                 static_data_reg = alloc_ireg (cfg);
10125                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10126
10127                                 if (cfg->compile_aot) {
10128                                         int offset_reg, offset2_reg, idx_reg;
10129
10130                                         /* For TLS variables, this will return the TLS offset */
10131                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10132                                         offset_reg = ins->dreg;
10133                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10134                                         idx_reg = alloc_ireg (cfg);
10135                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10136                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10137                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10138                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10139                                         array_reg = alloc_ireg (cfg);
10140                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10141                                         offset2_reg = alloc_ireg (cfg);
10142                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10143                                         dreg = alloc_ireg (cfg);
10144                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10145                                 } else {
10146                                         offset = (gsize)addr & 0x7fffffff;
10147                                         idx = (offset >> 24) - 1;
10148
10149                                         array_reg = alloc_ireg (cfg);
10150                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10151                                         dreg = alloc_ireg (cfg);
10152                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10153                                 }
10154                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10155                                         (cfg->compile_aot && is_special_static) ||
10156                                         (context_used && is_special_static)) {
10157                                 MonoInst *iargs [2];
10158
10159                                 g_assert (field->parent);
10160                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10161                                 if (context_used) {
10162                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10163                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10164                                 } else {
10165                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10166                                 }
10167                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10168                         } else if (context_used) {
10169                                 MonoInst *static_data;
10170
10171                                 /*
10172                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10173                                         method->klass->name_space, method->klass->name, method->name,
10174                                         depth, field->offset);
10175                                 */
10176
10177                                 if (mono_class_needs_cctor_run (klass, method))
10178                                         emit_generic_class_init (cfg, klass);
10179
10180                                 /*
10181                                  * The pointer we're computing here is
10182                                  *
10183                                  *   super_info.static_data + field->offset
10184                                  */
10185                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10186                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10187
10188                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10189                                         MonoInst *offset_ins;
10190
10191                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10192                                         dreg = alloc_ireg_mp (cfg);
10193                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10194                                 } else if (field->offset == 0) {
10195                                         ins = static_data;
10196                                 } else {
10197                                         int addr_reg = mono_alloc_preg (cfg);
10198                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10199                                 }
10200                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10201                                 MonoInst *iargs [2];
10202
10203                                 g_assert (field->parent);
10204                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10205                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10206                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10207                         } else {
10208                                 MonoVTable *vtable = NULL;
10209
10210                                 if (!cfg->compile_aot)
10211                                         vtable = mono_class_vtable (cfg->domain, klass);
10212                                 CHECK_TYPELOAD (klass);
10213
10214                                 if (!addr) {
10215                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10216                                                 if (!(g_slist_find (class_inits, klass))) {
10217                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10218                                                         if (cfg->verbose_level > 2)
10219                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10220                                                         class_inits = g_slist_prepend (class_inits, klass);
10221                                                 }
10222                                         } else {
10223                                                 if (cfg->run_cctors) {
10224                                                         MonoException *ex;
10225                                                         /* This makes so that inline cannot trigger */
10226                                                         /* .cctors: too many apps depend on them */
10227                                                         /* running with a specific order... */
10228                                                         g_assert (vtable);
10229                                                         if (! vtable->initialized)
10230                                                                 INLINE_FAILURE ("class init");
10231                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10232                                                         if (ex) {
10233                                                                 set_exception_object (cfg, ex);
10234                                                                 goto exception_exit;
10235                                                         }
10236                                                 }
10237                                         }
10238                                         if (cfg->compile_aot)
10239                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10240                                         else {
10241                                                 g_assert (vtable);
10242                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10243                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10244                                         }
10245                                 } else {
10246                                         MonoInst *iargs [1];
10247                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10248                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10249                                 }
10250                         }
10251
10252                         /* Generate IR to do the actual load/store operation */
10253
10254                         if (op == CEE_LDSFLDA) {
10255                                 ins->klass = mono_class_from_mono_type (ftype);
10256                                 ins->type = STACK_PTR;
10257                                 *sp++ = ins;
10258                         } else if (op == CEE_STSFLD) {
10259                                 MonoInst *store;
10260
10261                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10262                                 store->flags |= ins_flag;
10263                         } else {
10264                                 gboolean is_const = FALSE;
10265                                 MonoVTable *vtable = NULL;
10266                                 gpointer addr = NULL;
10267
10268                                 if (!context_used) {
10269                                         vtable = mono_class_vtable (cfg->domain, klass);
10270                                         CHECK_TYPELOAD (klass);
10271                                 }
10272                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10273                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10274                                         int ro_type = ftype->type;
10275                                         if (!addr)
10276                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10277                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10278                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10279                                         }
10280
10281                                         GSHAREDVT_FAILURE (op);
10282
10283                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10284                                         is_const = TRUE;
10285                                         switch (ro_type) {
10286                                         case MONO_TYPE_BOOLEAN:
10287                                         case MONO_TYPE_U1:
10288                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10289                                                 sp++;
10290                                                 break;
10291                                         case MONO_TYPE_I1:
10292                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10293                                                 sp++;
10294                                                 break;                                          
10295                                         case MONO_TYPE_CHAR:
10296                                         case MONO_TYPE_U2:
10297                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10298                                                 sp++;
10299                                                 break;
10300                                         case MONO_TYPE_I2:
10301                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10302                                                 sp++;
10303                                                 break;
10304                                                 break;
10305                                         case MONO_TYPE_I4:
10306                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10307                                                 sp++;
10308                                                 break;                                          
10309                                         case MONO_TYPE_U4:
10310                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10311                                                 sp++;
10312                                                 break;
10313                                         case MONO_TYPE_I:
10314                                         case MONO_TYPE_U:
10315                                         case MONO_TYPE_PTR:
10316                                         case MONO_TYPE_FNPTR:
10317                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10318                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10319                                                 sp++;
10320                                                 break;
10321                                         case MONO_TYPE_STRING:
10322                                         case MONO_TYPE_OBJECT:
10323                                         case MONO_TYPE_CLASS:
10324                                         case MONO_TYPE_SZARRAY:
10325                                         case MONO_TYPE_ARRAY:
10326                                                 if (!mono_gc_is_moving ()) {
10327                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10328                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10329                                                         sp++;
10330                                                 } else {
10331                                                         is_const = FALSE;
10332                                                 }
10333                                                 break;
10334                                         case MONO_TYPE_I8:
10335                                         case MONO_TYPE_U8:
10336                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10337                                                 sp++;
10338                                                 break;
10339                                         case MONO_TYPE_R4:
10340                                         case MONO_TYPE_R8:
10341                                         case MONO_TYPE_VALUETYPE:
10342                                         default:
10343                                                 is_const = FALSE;
10344                                                 break;
10345                                         }
10346                                 }
10347
10348                                 if (!is_const) {
10349                                         MonoInst *load;
10350
10351                                         CHECK_STACK_OVF (1);
10352
10353                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10354                                         load->flags |= ins_flag;
10355                                         ins_flag = 0;
10356                                         *sp++ = load;
10357                                 }
10358                         }
10359                         ins_flag = 0;
10360                         ip += 5;
10361                         break;
10362                 }
10363                 case CEE_STOBJ:
10364                         CHECK_STACK (2);
10365                         sp -= 2;
10366                         CHECK_OPSIZE (5);
10367                         token = read32 (ip + 1);
10368                         klass = mini_get_class (method, token, generic_context);
10369                         CHECK_TYPELOAD (klass);
10370                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10371                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10372                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10373                                         generic_class_is_reference_type (cfg, klass)) {
10374                                 /* insert call to write barrier */
10375                                 emit_write_barrier (cfg, sp [0], sp [1]);
10376                         }
10377                         ins_flag = 0;
10378                         ip += 5;
10379                         inline_costs += 1;
10380                         break;
10381
10382                         /*
10383                          * Array opcodes
10384                          */
10385                 case CEE_NEWARR: {
10386                         MonoInst *len_ins;
10387                         const char *data_ptr;
10388                         int data_size = 0;
10389                         guint32 field_token;
10390
10391                         CHECK_STACK (1);
10392                         --sp;
10393
10394                         CHECK_OPSIZE (5);
10395                         token = read32 (ip + 1);
10396
10397                         klass = mini_get_class (method, token, generic_context);
10398                         CHECK_TYPELOAD (klass);
10399
10400                         context_used = mini_class_check_context_used (cfg, klass);
10401
10402                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10403                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10404                                 ins->sreg1 = sp [0]->dreg;
10405                                 ins->type = STACK_I4;
10406                                 ins->dreg = alloc_ireg (cfg);
10407                                 MONO_ADD_INS (cfg->cbb, ins);
10408                                 *sp = mono_decompose_opcode (cfg, ins);
10409                         }
10410
10411                         if (context_used) {
10412                                 MonoInst *args [3];
10413                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10414                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10415
10416                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10417
10418                                 /* vtable */
10419                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10420                                         array_class, MONO_RGCTX_INFO_VTABLE);
10421                                 /* array len */
10422                                 args [1] = sp [0];
10423
10424                                 if (managed_alloc)
10425                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10426                                 else
10427                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10428                         } else {
10429                                 if (cfg->opt & MONO_OPT_SHARED) {
10430                                         /* Decompose now to avoid problems with references to the domainvar */
10431                                         MonoInst *iargs [3];
10432
10433                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10434                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10435                                         iargs [2] = sp [0];
10436
10437                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10438                                 } else {
10439                                         /* Decompose later since it is needed by abcrem */
10440                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10441                                         mono_class_vtable (cfg->domain, array_type);
10442                                         CHECK_TYPELOAD (array_type);
10443
10444                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10445                                         ins->dreg = alloc_ireg_ref (cfg);
10446                                         ins->sreg1 = sp [0]->dreg;
10447                                         ins->inst_newa_class = klass;
10448                                         ins->type = STACK_OBJ;
10449                                         ins->klass = array_type;
10450                                         MONO_ADD_INS (cfg->cbb, ins);
10451                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10452                                         cfg->cbb->has_array_access = TRUE;
10453
10454                                         /* Needed so mono_emit_load_get_addr () gets called */
10455                                         mono_get_got_var (cfg);
10456                                 }
10457                         }
10458
10459                         len_ins = sp [0];
10460                         ip += 5;
10461                         *sp++ = ins;
10462                         inline_costs += 1;
10463
10464                         /* 
10465                          * we inline/optimize the initialization sequence if possible.
10466                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10467                          * for small sizes open code the memcpy
10468                          * ensure the rva field is big enough
10469                          */
10470                         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))) {
10471                                 MonoMethod *memcpy_method = get_memcpy_method ();
10472                                 MonoInst *iargs [3];
10473                                 int add_reg = alloc_ireg_mp (cfg);
10474
10475                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10476                                 if (cfg->compile_aot) {
10477                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10478                                 } else {
10479                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10480                                 }
10481                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10482                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10483                                 ip += 11;
10484                         }
10485
10486                         break;
10487                 }
10488                 case CEE_LDLEN:
10489                         CHECK_STACK (1);
10490                         --sp;
10491                         if (sp [0]->type != STACK_OBJ)
10492                                 UNVERIFIED;
10493
10494                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10495                         ins->dreg = alloc_preg (cfg);
10496                         ins->sreg1 = sp [0]->dreg;
10497                         ins->type = STACK_I4;
10498                         /* This flag will be inherited by the decomposition */
10499                         ins->flags |= MONO_INST_FAULT;
10500                         MONO_ADD_INS (cfg->cbb, ins);
10501                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10502                         cfg->cbb->has_array_access = TRUE;
10503                         ip ++;
10504                         *sp++ = ins;
10505                         break;
10506                 case CEE_LDELEMA:
10507                         CHECK_STACK (2);
10508                         sp -= 2;
10509                         CHECK_OPSIZE (5);
10510                         if (sp [0]->type != STACK_OBJ)
10511                                 UNVERIFIED;
10512
10513                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10514
10515                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10516                         CHECK_TYPELOAD (klass);
10517                         /* we need to make sure that this array is exactly the type it needs
10518                          * to be for correctness. the wrappers are lax with their usage
10519                          * so we need to ignore them here
10520                          */
10521                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10522                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10523                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10524                                 CHECK_TYPELOAD (array_class);
10525                         }
10526
10527                         readonly = FALSE;
10528                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10529                         *sp++ = ins;
10530                         ip += 5;
10531                         break;
10532                 case CEE_LDELEM:
10533                 case CEE_LDELEM_I1:
10534                 case CEE_LDELEM_U1:
10535                 case CEE_LDELEM_I2:
10536                 case CEE_LDELEM_U2:
10537                 case CEE_LDELEM_I4:
10538                 case CEE_LDELEM_U4:
10539                 case CEE_LDELEM_I8:
10540                 case CEE_LDELEM_I:
10541                 case CEE_LDELEM_R4:
10542                 case CEE_LDELEM_R8:
10543                 case CEE_LDELEM_REF: {
10544                         MonoInst *addr;
10545
10546                         CHECK_STACK (2);
10547                         sp -= 2;
10548
10549                         if (*ip == CEE_LDELEM) {
10550                                 CHECK_OPSIZE (5);
10551                                 token = read32 (ip + 1);
10552                                 klass = mini_get_class (method, token, generic_context);
10553                                 CHECK_TYPELOAD (klass);
10554                                 mono_class_init (klass);
10555                         }
10556                         else
10557                                 klass = array_access_to_klass (*ip);
10558
10559                         if (sp [0]->type != STACK_OBJ)
10560                                 UNVERIFIED;
10561
10562                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10563
10564                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10565                                 // FIXME-VT: OP_ICONST optimization
10566                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10567                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10568                                 ins->opcode = OP_LOADV_MEMBASE;
10569                         } else if (sp [1]->opcode == OP_ICONST) {
10570                                 int array_reg = sp [0]->dreg;
10571                                 int index_reg = sp [1]->dreg;
10572                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10573
10574                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10575                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10576                         } else {
10577                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10578                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10579                         }
10580                         *sp++ = ins;
10581                         if (*ip == CEE_LDELEM)
10582                                 ip += 5;
10583                         else
10584                                 ++ip;
10585                         break;
10586                 }
10587                 case CEE_STELEM_I:
10588                 case CEE_STELEM_I1:
10589                 case CEE_STELEM_I2:
10590                 case CEE_STELEM_I4:
10591                 case CEE_STELEM_I8:
10592                 case CEE_STELEM_R4:
10593                 case CEE_STELEM_R8:
10594                 case CEE_STELEM_REF:
10595                 case CEE_STELEM: {
10596                         CHECK_STACK (3);
10597                         sp -= 3;
10598
10599                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10600
10601                         if (*ip == CEE_STELEM) {
10602                                 CHECK_OPSIZE (5);
10603                                 token = read32 (ip + 1);
10604                                 klass = mini_get_class (method, token, generic_context);
10605                                 CHECK_TYPELOAD (klass);
10606                                 mono_class_init (klass);
10607                         }
10608                         else
10609                                 klass = array_access_to_klass (*ip);
10610
10611                         if (sp [0]->type != STACK_OBJ)
10612                                 UNVERIFIED;
10613
10614                         emit_array_store (cfg, klass, sp, TRUE);
10615
10616                         if (*ip == CEE_STELEM)
10617                                 ip += 5;
10618                         else
10619                                 ++ip;
10620                         inline_costs += 1;
10621                         break;
10622                 }
10623                 case CEE_CKFINITE: {
10624                         CHECK_STACK (1);
10625                         --sp;
10626
10627                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10628                         ins->sreg1 = sp [0]->dreg;
10629                         ins->dreg = alloc_freg (cfg);
10630                         ins->type = STACK_R8;
10631                         MONO_ADD_INS (bblock, ins);
10632
10633                         *sp++ = mono_decompose_opcode (cfg, ins);
10634
10635                         ++ip;
10636                         break;
10637                 }
10638                 case CEE_REFANYVAL: {
10639                         MonoInst *src_var, *src;
10640
10641                         int klass_reg = alloc_preg (cfg);
10642                         int dreg = alloc_preg (cfg);
10643
10644                         GSHAREDVT_FAILURE (*ip);
10645
10646                         CHECK_STACK (1);
10647                         MONO_INST_NEW (cfg, ins, *ip);
10648                         --sp;
10649                         CHECK_OPSIZE (5);
10650                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10651                         CHECK_TYPELOAD (klass);
10652                         mono_class_init (klass);
10653
10654                         context_used = mini_class_check_context_used (cfg, klass);
10655
10656                         // FIXME:
10657                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10658                         if (!src_var)
10659                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10660                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10661                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10662
10663                         if (context_used) {
10664                                 MonoInst *klass_ins;
10665
10666                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10667                                                 klass, MONO_RGCTX_INFO_KLASS);
10668
10669                                 // FIXME:
10670                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10671                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10672                         } else {
10673                                 mini_emit_class_check (cfg, klass_reg, klass);
10674                         }
10675                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10676                         ins->type = STACK_MP;
10677                         *sp++ = ins;
10678                         ip += 5;
10679                         break;
10680                 }
10681                 case CEE_MKREFANY: {
10682                         MonoInst *loc, *addr;
10683
10684                         GSHAREDVT_FAILURE (*ip);
10685
10686                         CHECK_STACK (1);
10687                         MONO_INST_NEW (cfg, ins, *ip);
10688                         --sp;
10689                         CHECK_OPSIZE (5);
10690                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10691                         CHECK_TYPELOAD (klass);
10692                         mono_class_init (klass);
10693
10694                         context_used = mini_class_check_context_used (cfg, klass);
10695
10696                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10697                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10698
10699                         if (context_used) {
10700                                 MonoInst *const_ins;
10701                                 int type_reg = alloc_preg (cfg);
10702
10703                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10704                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10705                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10706                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10707                         } else if (cfg->compile_aot) {
10708                                 int const_reg = alloc_preg (cfg);
10709                                 int type_reg = alloc_preg (cfg);
10710
10711                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10712                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10713                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10714                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10715                         } else {
10716                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10717                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10718                         }
10719                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10720
10721                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10722                         ins->type = STACK_VTYPE;
10723                         ins->klass = mono_defaults.typed_reference_class;
10724                         *sp++ = ins;
10725                         ip += 5;
10726                         break;
10727                 }
10728                 case CEE_LDTOKEN: {
10729                         gpointer handle;
10730                         MonoClass *handle_class;
10731
10732                         CHECK_STACK_OVF (1);
10733
10734                         CHECK_OPSIZE (5);
10735                         n = read32 (ip + 1);
10736
10737                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10738                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10739                                 handle = mono_method_get_wrapper_data (method, n);
10740                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10741                                 if (handle_class == mono_defaults.typehandle_class)
10742                                         handle = &((MonoClass*)handle)->byval_arg;
10743                         }
10744                         else {
10745                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10746                         }
10747                         if (!handle)
10748                                 LOAD_ERROR;
10749                         mono_class_init (handle_class);
10750                         if (cfg->generic_sharing_context) {
10751                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10752                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10753                                         /* This case handles ldtoken
10754                                            of an open type, like for
10755                                            typeof(Gen<>). */
10756                                         context_used = 0;
10757                                 } else if (handle_class == mono_defaults.typehandle_class) {
10758                                         /* If we get a MONO_TYPE_CLASS
10759                                            then we need to provide the
10760                                            open type, not an
10761                                            instantiation of it. */
10762                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10763                                                 context_used = 0;
10764                                         else
10765                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10766                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10767                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10768                                 else if (handle_class == mono_defaults.methodhandle_class)
10769                                         context_used = mini_method_check_context_used (cfg, handle);
10770                                 else
10771                                         g_assert_not_reached ();
10772                         }
10773
10774                         if ((cfg->opt & MONO_OPT_SHARED) &&
10775                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10776                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10777                                 MonoInst *addr, *vtvar, *iargs [3];
10778                                 int method_context_used;
10779
10780                                 method_context_used = mini_method_check_context_used (cfg, method);
10781
10782                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10783
10784                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10785                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10786                                 if (method_context_used) {
10787                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10788                                                 method, MONO_RGCTX_INFO_METHOD);
10789                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10790                                 } else {
10791                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10792                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10793                                 }
10794                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10795
10796                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10797
10798                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10799                         } else {
10800                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10801                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10802                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10803                                         (cmethod->klass == mono_defaults.systemtype_class) &&
10804                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10805                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10806
10807                                         mono_class_init (tclass);
10808                                         if (context_used) {
10809                                                 ins = emit_get_rgctx_klass (cfg, context_used,
10810                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
10811                                         } else if (cfg->compile_aot) {
10812                                                 if (method->wrapper_type) {
10813                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
10814                                                                 /* Special case for static synchronized wrappers */
10815                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
10816                                                         } else {
10817                                                                 /* FIXME: n is not a normal token */
10818                                                                 cfg->disable_aot = TRUE;
10819                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
10820                                                         }
10821                                                 } else {
10822                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
10823                                                 }
10824                                         } else {
10825                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
10826                                         }
10827                                         ins->type = STACK_OBJ;
10828                                         ins->klass = cmethod->klass;
10829                                         ip += 5;
10830                                 } else {
10831                                         MonoInst *addr, *vtvar;
10832
10833                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
10834
10835                                         if (context_used) {
10836                                                 if (handle_class == mono_defaults.typehandle_class) {
10837                                                         ins = emit_get_rgctx_klass (cfg, context_used,
10838                                                                         mono_class_from_mono_type (handle),
10839                                                                         MONO_RGCTX_INFO_TYPE);
10840                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
10841                                                         ins = emit_get_rgctx_method (cfg, context_used,
10842                                                                         handle, MONO_RGCTX_INFO_METHOD);
10843                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
10844                                                         ins = emit_get_rgctx_field (cfg, context_used,
10845                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
10846                                                 } else {
10847                                                         g_assert_not_reached ();
10848                                                 }
10849                                         } else if (cfg->compile_aot) {
10850                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
10851                                         } else {
10852                                                 EMIT_NEW_PCONST (cfg, ins, handle);
10853                                         }
10854                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10855                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10856                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10857                                 }
10858                         }
10859
10860                         *sp++ = ins;
10861                         ip += 5;
10862                         break;
10863                 }
10864                 case CEE_THROW:
10865                         CHECK_STACK (1);
10866                         MONO_INST_NEW (cfg, ins, OP_THROW);
10867                         --sp;
10868                         ins->sreg1 = sp [0]->dreg;
10869                         ip++;
10870                         bblock->out_of_line = TRUE;
10871                         MONO_ADD_INS (bblock, ins);
10872                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10873                         MONO_ADD_INS (bblock, ins);
10874                         sp = stack_start;
10875                         
10876                         link_bblock (cfg, bblock, end_bblock);
10877                         start_new_bblock = 1;
10878                         break;
10879                 case CEE_ENDFINALLY:
10880                         /* mono_save_seq_point_info () depends on this */
10881                         if (sp != stack_start)
10882                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
10883                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
10884                         MONO_ADD_INS (bblock, ins);
10885                         ip++;
10886                         start_new_bblock = 1;
10887
10888                         /*
10889                          * Control will leave the method so empty the stack, otherwise
10890                          * the next basic block will start with a nonempty stack.
10891                          */
10892                         while (sp != stack_start) {
10893                                 sp--;
10894                         }
10895                         break;
10896                 case CEE_LEAVE:
10897                 case CEE_LEAVE_S: {
10898                         GList *handlers;
10899
10900                         if (*ip == CEE_LEAVE) {
10901                                 CHECK_OPSIZE (5);
10902                                 target = ip + 5 + (gint32)read32(ip + 1);
10903                         } else {
10904                                 CHECK_OPSIZE (2);
10905                                 target = ip + 2 + (signed char)(ip [1]);
10906                         }
10907
10908                         /* empty the stack */
10909                         while (sp != stack_start) {
10910                                 sp--;
10911                         }
10912
10913                         /* 
10914                          * If this leave statement is in a catch block, check for a
10915                          * pending exception, and rethrow it if necessary.
10916                          * We avoid doing this in runtime invoke wrappers, since those are called
10917                          * by native code which excepts the wrapper to catch all exceptions.
10918                          */
10919                         for (i = 0; i < header->num_clauses; ++i) {
10920                                 MonoExceptionClause *clause = &header->clauses [i];
10921
10922                                 /* 
10923                                  * Use <= in the final comparison to handle clauses with multiple
10924                                  * leave statements, like in bug #78024.
10925                                  * The ordering of the exception clauses guarantees that we find the
10926                                  * innermost clause.
10927                                  */
10928                                 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) {
10929                                         MonoInst *exc_ins;
10930                                         MonoBasicBlock *dont_throw;
10931
10932                                         /*
10933                                           MonoInst *load;
10934
10935                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
10936                                         */
10937
10938                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
10939
10940                                         NEW_BBLOCK (cfg, dont_throw);
10941
10942                                         /*
10943                                          * Currently, we always rethrow the abort exception, despite the 
10944                                          * fact that this is not correct. See thread6.cs for an example. 
10945                                          * But propagating the abort exception is more important than 
10946                                          * getting the sematics right.
10947                                          */
10948                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
10949                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
10950                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
10951
10952                                         MONO_START_BB (cfg, dont_throw);
10953                                         bblock = cfg->cbb;
10954                                 }
10955                         }
10956
10957                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
10958                                 GList *tmp;
10959                                 MonoExceptionClause *clause;
10960
10961                                 for (tmp = handlers; tmp; tmp = tmp->next) {
10962                                         clause = tmp->data;
10963                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
10964                                         g_assert (tblock);
10965                                         link_bblock (cfg, bblock, tblock);
10966                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
10967                                         ins->inst_target_bb = tblock;
10968                                         ins->inst_eh_block = clause;
10969                                         MONO_ADD_INS (bblock, ins);
10970                                         bblock->has_call_handler = 1;
10971                                         if (COMPILE_LLVM (cfg)) {
10972                                                 MonoBasicBlock *target_bb;
10973
10974                                                 /* 
10975                                                  * Link the finally bblock with the target, since it will
10976                                                  * conceptually branch there.
10977                                                  * FIXME: Have to link the bblock containing the endfinally.
10978                                                  */
10979                                                 GET_BBLOCK (cfg, target_bb, target);
10980                                                 link_bblock (cfg, tblock, target_bb);
10981                                         }
10982                                 }
10983                                 g_list_free (handlers);
10984                         } 
10985
10986                         MONO_INST_NEW (cfg, ins, OP_BR);
10987                         MONO_ADD_INS (bblock, ins);
10988                         GET_BBLOCK (cfg, tblock, target);
10989                         link_bblock (cfg, bblock, tblock);
10990                         ins->inst_target_bb = tblock;
10991                         start_new_bblock = 1;
10992
10993                         if (*ip == CEE_LEAVE)
10994                                 ip += 5;
10995                         else
10996                                 ip += 2;
10997
10998                         break;
10999                 }
11000
11001                         /*
11002                          * Mono specific opcodes
11003                          */
11004                 case MONO_CUSTOM_PREFIX: {
11005
11006                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11007
11008                         CHECK_OPSIZE (2);
11009                         switch (ip [1]) {
11010                         case CEE_MONO_ICALL: {
11011                                 gpointer func;
11012                                 MonoJitICallInfo *info;
11013
11014                                 token = read32 (ip + 2);
11015                                 func = mono_method_get_wrapper_data (method, token);
11016                                 info = mono_find_jit_icall_by_addr (func);
11017                                 if (!info)
11018                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11019                                 g_assert (info);
11020
11021                                 CHECK_STACK (info->sig->param_count);
11022                                 sp -= info->sig->param_count;
11023
11024                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11025                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11026                                         *sp++ = ins;
11027
11028                                 ip += 6;
11029                                 inline_costs += 10 * num_calls++;
11030
11031                                 break;
11032                         }
11033                         case CEE_MONO_LDPTR: {
11034                                 gpointer ptr;
11035
11036                                 CHECK_STACK_OVF (1);
11037                                 CHECK_OPSIZE (6);
11038                                 token = read32 (ip + 2);
11039
11040                                 ptr = mono_method_get_wrapper_data (method, token);
11041                                 /* FIXME: Generalize this */
11042                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11043                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11044                                         *sp++ = ins;
11045                                         ip += 6;
11046                                         break;
11047                                 }
11048                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11049                                 *sp++ = ins;
11050                                 ip += 6;
11051                                 inline_costs += 10 * num_calls++;
11052                                 /* Can't embed random pointers into AOT code */
11053                                 cfg->disable_aot = 1;
11054                                 break;
11055                         }
11056                         case CEE_MONO_JIT_ICALL_ADDR: {
11057                                 MonoJitICallInfo *callinfo;
11058                                 gpointer ptr;
11059
11060                                 CHECK_STACK_OVF (1);
11061                                 CHECK_OPSIZE (6);
11062                                 token = read32 (ip + 2);
11063
11064                                 ptr = mono_method_get_wrapper_data (method, token);
11065                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11066                                 g_assert (callinfo);
11067                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11068                                 *sp++ = ins;
11069                                 ip += 6;
11070                                 inline_costs += 10 * num_calls++;
11071                                 break;
11072                         }
11073                         case CEE_MONO_ICALL_ADDR: {
11074                                 MonoMethod *cmethod;
11075                                 gpointer ptr;
11076
11077                                 CHECK_STACK_OVF (1);
11078                                 CHECK_OPSIZE (6);
11079                                 token = read32 (ip + 2);
11080
11081                                 cmethod = mono_method_get_wrapper_data (method, token);
11082
11083                                 if (cfg->compile_aot) {
11084                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11085                                 } else {
11086                                         ptr = mono_lookup_internal_call (cmethod);
11087                                         g_assert (ptr);
11088                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11089                                 }
11090                                 *sp++ = ins;
11091                                 ip += 6;
11092                                 break;
11093                         }
11094                         case CEE_MONO_VTADDR: {
11095                                 MonoInst *src_var, *src;
11096
11097                                 CHECK_STACK (1);
11098                                 --sp;
11099
11100                                 // FIXME:
11101                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11102                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11103                                 *sp++ = src;
11104                                 ip += 2;
11105                                 break;
11106                         }
11107                         case CEE_MONO_NEWOBJ: {
11108                                 MonoInst *iargs [2];
11109
11110                                 CHECK_STACK_OVF (1);
11111                                 CHECK_OPSIZE (6);
11112                                 token = read32 (ip + 2);
11113                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11114                                 mono_class_init (klass);
11115                                 NEW_DOMAINCONST (cfg, iargs [0]);
11116                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11117                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11118                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11119                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11120                                 ip += 6;
11121                                 inline_costs += 10 * num_calls++;
11122                                 break;
11123                         }
11124                         case CEE_MONO_OBJADDR:
11125                                 CHECK_STACK (1);
11126                                 --sp;
11127                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11128                                 ins->dreg = alloc_ireg_mp (cfg);
11129                                 ins->sreg1 = sp [0]->dreg;
11130                                 ins->type = STACK_MP;
11131                                 MONO_ADD_INS (cfg->cbb, ins);
11132                                 *sp++ = ins;
11133                                 ip += 2;
11134                                 break;
11135                         case CEE_MONO_LDNATIVEOBJ:
11136                                 /*
11137                                  * Similar to LDOBJ, but instead load the unmanaged 
11138                                  * representation of the vtype to the stack.
11139                                  */
11140                                 CHECK_STACK (1);
11141                                 CHECK_OPSIZE (6);
11142                                 --sp;
11143                                 token = read32 (ip + 2);
11144                                 klass = mono_method_get_wrapper_data (method, token);
11145                                 g_assert (klass->valuetype);
11146                                 mono_class_init (klass);
11147
11148                                 {
11149                                         MonoInst *src, *dest, *temp;
11150
11151                                         src = sp [0];
11152                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11153                                         temp->backend.is_pinvoke = 1;
11154                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11155                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11156
11157                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11158                                         dest->type = STACK_VTYPE;
11159                                         dest->klass = klass;
11160
11161                                         *sp ++ = dest;
11162                                         ip += 6;
11163                                 }
11164                                 break;
11165                         case CEE_MONO_RETOBJ: {
11166                                 /*
11167                                  * Same as RET, but return the native representation of a vtype
11168                                  * to the caller.
11169                                  */
11170                                 g_assert (cfg->ret);
11171                                 g_assert (mono_method_signature (method)->pinvoke); 
11172                                 CHECK_STACK (1);
11173                                 --sp;
11174                                 
11175                                 CHECK_OPSIZE (6);
11176                                 token = read32 (ip + 2);    
11177                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11178
11179                                 if (!cfg->vret_addr) {
11180                                         g_assert (cfg->ret_var_is_local);
11181
11182                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11183                                 } else {
11184                                         EMIT_NEW_RETLOADA (cfg, ins);
11185                                 }
11186                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11187                                 
11188                                 if (sp != stack_start)
11189                                         UNVERIFIED;
11190                                 
11191                                 MONO_INST_NEW (cfg, ins, OP_BR);
11192                                 ins->inst_target_bb = end_bblock;
11193                                 MONO_ADD_INS (bblock, ins);
11194                                 link_bblock (cfg, bblock, end_bblock);
11195                                 start_new_bblock = 1;
11196                                 ip += 6;
11197                                 break;
11198                         }
11199                         case CEE_MONO_CISINST:
11200                         case CEE_MONO_CCASTCLASS: {
11201                                 int token;
11202                                 CHECK_STACK (1);
11203                                 --sp;
11204                                 CHECK_OPSIZE (6);
11205                                 token = read32 (ip + 2);
11206                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11207                                 if (ip [1] == CEE_MONO_CISINST)
11208                                         ins = handle_cisinst (cfg, klass, sp [0]);
11209                                 else
11210                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11211                                 bblock = cfg->cbb;
11212                                 *sp++ = ins;
11213                                 ip += 6;
11214                                 break;
11215                         }
11216                         case CEE_MONO_SAVE_LMF:
11217                         case CEE_MONO_RESTORE_LMF:
11218 #ifdef MONO_ARCH_HAVE_LMF_OPS
11219                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11220                                 MONO_ADD_INS (bblock, ins);
11221                                 cfg->need_lmf_area = TRUE;
11222 #endif
11223                                 ip += 2;
11224                                 break;
11225                         case CEE_MONO_CLASSCONST:
11226                                 CHECK_STACK_OVF (1);
11227                                 CHECK_OPSIZE (6);
11228                                 token = read32 (ip + 2);
11229                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11230                                 *sp++ = ins;
11231                                 ip += 6;
11232                                 inline_costs += 10 * num_calls++;
11233                                 break;
11234                         case CEE_MONO_NOT_TAKEN:
11235                                 bblock->out_of_line = TRUE;
11236                                 ip += 2;
11237                                 break;
11238                         case CEE_MONO_TLS: {
11239                                 int key;
11240
11241                                 CHECK_STACK_OVF (1);
11242                                 CHECK_OPSIZE (6);
11243                                 key = (gint32)read32 (ip + 2);
11244                                 g_assert (key < TLS_KEY_NUM);
11245
11246                                 ins = mono_create_tls_get (cfg, key);
11247                                 if (!ins) {
11248                                         if (cfg->compile_aot) {
11249                                                 cfg->disable_aot = TRUE;
11250                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11251                                                 ins->dreg = alloc_preg (cfg);
11252                                                 ins->type = STACK_PTR;
11253                                         } else {
11254                                                 g_assert_not_reached ();
11255                                         }
11256                                 }
11257                                 ins->type = STACK_PTR;
11258                                 MONO_ADD_INS (bblock, ins);
11259                                 *sp++ = ins;
11260                                 ip += 6;
11261                                 break;
11262                         }
11263                         case CEE_MONO_DYN_CALL: {
11264                                 MonoCallInst *call;
11265
11266                                 /* It would be easier to call a trampoline, but that would put an
11267                                  * extra frame on the stack, confusing exception handling. So
11268                                  * implement it inline using an opcode for now.
11269                                  */
11270
11271                                 if (!cfg->dyn_call_var) {
11272                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11273                                         /* prevent it from being register allocated */
11274                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11275                                 }
11276
11277                                 /* Has to use a call inst since it local regalloc expects it */
11278                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11279                                 ins = (MonoInst*)call;
11280                                 sp -= 2;
11281                                 ins->sreg1 = sp [0]->dreg;
11282                                 ins->sreg2 = sp [1]->dreg;
11283                                 MONO_ADD_INS (bblock, ins);
11284
11285                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11286
11287                                 ip += 2;
11288                                 inline_costs += 10 * num_calls++;
11289
11290                                 break;
11291                         }
11292                         case CEE_MONO_MEMORY_BARRIER: {
11293                                 CHECK_OPSIZE (5);
11294                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11295                                 ip += 5;
11296                                 break;
11297                         }
11298                         case CEE_MONO_JIT_ATTACH: {
11299                                 MonoInst *args [16];
11300                                 MonoInst *ad_ins, *lmf_ins;
11301                                 MonoBasicBlock *next_bb = NULL;
11302
11303                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11304
11305                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11306                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11307
11308 #if TARGET_WIN32
11309                                 ad_ins = NULL;
11310                                 lmf_ins = NULL;
11311 #else
11312                                 ad_ins = mono_get_domain_intrinsic (cfg);
11313                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11314 #endif
11315
11316                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11317                                         NEW_BBLOCK (cfg, next_bb);
11318
11319                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11320                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11321                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11322
11323                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11324                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11325                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11326                                 }
11327
11328                                 if (cfg->compile_aot) {
11329                                         /* AOT code is only used in the root domain */
11330                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11331                                 } else {
11332                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11333                                 }
11334                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11335                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11336
11337                                 if (next_bb) {
11338                                         MONO_START_BB (cfg, next_bb);
11339                                         bblock = cfg->cbb;
11340                                 }
11341                                 ip += 2;
11342                                 break;
11343                         }
11344                         case CEE_MONO_JIT_DETACH: {
11345                                 MonoInst *args [16];
11346
11347                                 /* Restore the original domain */
11348                                 dreg = alloc_ireg (cfg);
11349                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11350                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11351                                 ip += 2;
11352                                 break;
11353                         }
11354                         default:
11355                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11356                                 break;
11357                         }
11358                         break;
11359                 }
11360
11361                 case CEE_PREFIX1: {
11362                         CHECK_OPSIZE (2);
11363                         switch (ip [1]) {
11364                         case CEE_ARGLIST: {
11365                                 /* somewhat similar to LDTOKEN */
11366                                 MonoInst *addr, *vtvar;
11367                                 CHECK_STACK_OVF (1);
11368                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11369
11370                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11371                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11372
11373                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11374                                 ins->type = STACK_VTYPE;
11375                                 ins->klass = mono_defaults.argumenthandle_class;
11376                                 *sp++ = ins;
11377                                 ip += 2;
11378                                 break;
11379                         }
11380                         case CEE_CEQ:
11381                         case CEE_CGT:
11382                         case CEE_CGT_UN:
11383                         case CEE_CLT:
11384                         case CEE_CLT_UN: {
11385                                 MonoInst *cmp;
11386                                 CHECK_STACK (2);
11387                                 /*
11388                                  * The following transforms:
11389                                  *    CEE_CEQ    into OP_CEQ
11390                                  *    CEE_CGT    into OP_CGT
11391                                  *    CEE_CGT_UN into OP_CGT_UN
11392                                  *    CEE_CLT    into OP_CLT
11393                                  *    CEE_CLT_UN into OP_CLT_UN
11394                                  */
11395                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11396                                 
11397                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11398                                 sp -= 2;
11399                                 cmp->sreg1 = sp [0]->dreg;
11400                                 cmp->sreg2 = sp [1]->dreg;
11401                                 type_from_op (cmp, sp [0], sp [1]);
11402                                 CHECK_TYPE (cmp);
11403                                 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))))
11404                                         cmp->opcode = OP_LCOMPARE;
11405                                 else if (sp [0]->type == STACK_R8)
11406                                         cmp->opcode = OP_FCOMPARE;
11407                                 else
11408                                         cmp->opcode = OP_ICOMPARE;
11409                                 MONO_ADD_INS (bblock, cmp);
11410                                 ins->type = STACK_I4;
11411                                 ins->dreg = alloc_dreg (cfg, ins->type);
11412                                 type_from_op (ins, sp [0], sp [1]);
11413
11414                                 if (cmp->opcode == OP_FCOMPARE) {
11415                                         /*
11416                                          * The backends expect the fceq opcodes to do the
11417                                          * comparison too.
11418                                          */
11419                                         cmp->opcode = OP_NOP;
11420                                         ins->sreg1 = cmp->sreg1;
11421                                         ins->sreg2 = cmp->sreg2;
11422                                 }
11423                                 MONO_ADD_INS (bblock, ins);
11424                                 *sp++ = ins;
11425                                 ip += 2;
11426                                 break;
11427                         }
11428                         case CEE_LDFTN: {
11429                                 MonoInst *argconst;
11430                                 MonoMethod *cil_method;
11431
11432                                 CHECK_STACK_OVF (1);
11433                                 CHECK_OPSIZE (6);
11434                                 n = read32 (ip + 2);
11435                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11436                                 if (!cmethod || mono_loader_get_last_error ())
11437                                         LOAD_ERROR;
11438                                 mono_class_init (cmethod->klass);
11439
11440                                 mono_save_token_info (cfg, image, n, cmethod);
11441
11442                                 context_used = mini_method_check_context_used (cfg, cmethod);
11443
11444                                 cil_method = cmethod;
11445                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11446                                         METHOD_ACCESS_FAILURE;
11447
11448                                 if (mono_security_cas_enabled ()) {
11449                                         if (check_linkdemand (cfg, method, cmethod))
11450                                                 INLINE_FAILURE ("linkdemand");
11451                                         CHECK_CFG_EXCEPTION;
11452                                 } else if (mono_security_core_clr_enabled ()) {
11453                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11454                                 }
11455
11456                                 /* 
11457                                  * Optimize the common case of ldftn+delegate creation
11458                                  */
11459                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11460                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11461                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11462                                                 MonoInst *target_ins;
11463                                                 MonoMethod *invoke;
11464                                                 int invoke_context_used;
11465
11466                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11467                                                 if (!invoke || !mono_method_signature (invoke))
11468                                                         LOAD_ERROR;
11469
11470                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11471
11472                                                 target_ins = sp [-1];
11473
11474                                                 if (mono_security_core_clr_enabled ())
11475                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11476
11477                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11478                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11479                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11480                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11481                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11482                                                         }
11483                                                 }
11484
11485 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11486                                                 /* FIXME: SGEN support */
11487                                                 if (invoke_context_used == 0) {
11488                                                         ip += 6;
11489                                                         if (cfg->verbose_level > 3)
11490                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11491                                                         sp --;
11492                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11493                                                         CHECK_CFG_EXCEPTION;
11494                                                         ip += 5;                        
11495                                                         sp ++;
11496                                                         break;
11497                                                 }
11498 #endif
11499                                         }
11500                                 }
11501
11502                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11503                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11504                                 *sp++ = ins;
11505                                 
11506                                 ip += 6;
11507                                 inline_costs += 10 * num_calls++;
11508                                 break;
11509                         }
11510                         case CEE_LDVIRTFTN: {
11511                                 MonoInst *args [2];
11512
11513                                 CHECK_STACK (1);
11514                                 CHECK_OPSIZE (6);
11515                                 n = read32 (ip + 2);
11516                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11517                                 if (!cmethod || mono_loader_get_last_error ())
11518                                         LOAD_ERROR;
11519                                 mono_class_init (cmethod->klass);
11520  
11521                                 context_used = mini_method_check_context_used (cfg, cmethod);
11522
11523                                 if (mono_security_cas_enabled ()) {
11524                                         if (check_linkdemand (cfg, method, cmethod))
11525                                                 INLINE_FAILURE ("linkdemand");
11526                                         CHECK_CFG_EXCEPTION;
11527                                 } else if (mono_security_core_clr_enabled ()) {
11528                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11529                                 }
11530
11531                                 --sp;
11532                                 args [0] = *sp;
11533
11534                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11535                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11536
11537                                 if (context_used)
11538                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11539                                 else
11540                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11541
11542                                 ip += 6;
11543                                 inline_costs += 10 * num_calls++;
11544                                 break;
11545                         }
11546                         case CEE_LDARG:
11547                                 CHECK_STACK_OVF (1);
11548                                 CHECK_OPSIZE (4);
11549                                 n = read16 (ip + 2);
11550                                 CHECK_ARG (n);
11551                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11552                                 *sp++ = ins;
11553                                 ip += 4;
11554                                 break;
11555                         case CEE_LDARGA:
11556                                 CHECK_STACK_OVF (1);
11557                                 CHECK_OPSIZE (4);
11558                                 n = read16 (ip + 2);
11559                                 CHECK_ARG (n);
11560                                 NEW_ARGLOADA (cfg, ins, n);
11561                                 MONO_ADD_INS (cfg->cbb, ins);
11562                                 *sp++ = ins;
11563                                 ip += 4;
11564                                 break;
11565                         case CEE_STARG:
11566                                 CHECK_STACK (1);
11567                                 --sp;
11568                                 CHECK_OPSIZE (4);
11569                                 n = read16 (ip + 2);
11570                                 CHECK_ARG (n);
11571                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11572                                         UNVERIFIED;
11573                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11574                                 ip += 4;
11575                                 break;
11576                         case CEE_LDLOC:
11577                                 CHECK_STACK_OVF (1);
11578                                 CHECK_OPSIZE (4);
11579                                 n = read16 (ip + 2);
11580                                 CHECK_LOCAL (n);
11581                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11582                                 *sp++ = ins;
11583                                 ip += 4;
11584                                 break;
11585                         case CEE_LDLOCA: {
11586                                 unsigned char *tmp_ip;
11587                                 CHECK_STACK_OVF (1);
11588                                 CHECK_OPSIZE (4);
11589                                 n = read16 (ip + 2);
11590                                 CHECK_LOCAL (n);
11591
11592                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11593                                         ip = tmp_ip;
11594                                         inline_costs += 1;
11595                                         break;
11596                                 }                       
11597                                 
11598                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11599                                 *sp++ = ins;
11600                                 ip += 4;
11601                                 break;
11602                         }
11603                         case CEE_STLOC:
11604                                 CHECK_STACK (1);
11605                                 --sp;
11606                                 CHECK_OPSIZE (4);
11607                                 n = read16 (ip + 2);
11608                                 CHECK_LOCAL (n);
11609                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11610                                         UNVERIFIED;
11611                                 emit_stloc_ir (cfg, sp, header, n);
11612                                 ip += 4;
11613                                 inline_costs += 1;
11614                                 break;
11615                         case CEE_LOCALLOC:
11616                                 CHECK_STACK (1);
11617                                 --sp;
11618                                 if (sp != stack_start) 
11619                                         UNVERIFIED;
11620                                 if (cfg->method != method) 
11621                                         /* 
11622                                          * Inlining this into a loop in a parent could lead to 
11623                                          * stack overflows which is different behavior than the
11624                                          * non-inlined case, thus disable inlining in this case.
11625                                          */
11626                                         goto inline_failure;
11627
11628                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11629                                 ins->dreg = alloc_preg (cfg);
11630                                 ins->sreg1 = sp [0]->dreg;
11631                                 ins->type = STACK_PTR;
11632                                 MONO_ADD_INS (cfg->cbb, ins);
11633
11634                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11635                                 if (init_locals)
11636                                         ins->flags |= MONO_INST_INIT;
11637
11638                                 *sp++ = ins;
11639                                 ip += 2;
11640                                 break;
11641                         case CEE_ENDFILTER: {
11642                                 MonoExceptionClause *clause, *nearest;
11643                                 int cc, nearest_num;
11644
11645                                 CHECK_STACK (1);
11646                                 --sp;
11647                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11648                                         UNVERIFIED;
11649                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11650                                 ins->sreg1 = (*sp)->dreg;
11651                                 MONO_ADD_INS (bblock, ins);
11652                                 start_new_bblock = 1;
11653                                 ip += 2;
11654
11655                                 nearest = NULL;
11656                                 nearest_num = 0;
11657                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11658                                         clause = &header->clauses [cc];
11659                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11660                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11661                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11662                                                 nearest = clause;
11663                                                 nearest_num = cc;
11664                                         }
11665                                 }
11666                                 g_assert (nearest);
11667                                 if ((ip - header->code) != nearest->handler_offset)
11668                                         UNVERIFIED;
11669
11670                                 break;
11671                         }
11672                         case CEE_UNALIGNED_:
11673                                 ins_flag |= MONO_INST_UNALIGNED;
11674                                 /* FIXME: record alignment? we can assume 1 for now */
11675                                 CHECK_OPSIZE (3);
11676                                 ip += 3;
11677                                 break;
11678                         case CEE_VOLATILE_:
11679                                 ins_flag |= MONO_INST_VOLATILE;
11680                                 ip += 2;
11681                                 break;
11682                         case CEE_TAIL_:
11683                                 ins_flag   |= MONO_INST_TAILCALL;
11684                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11685                                 /* Can't inline tail calls at this time */
11686                                 inline_costs += 100000;
11687                                 ip += 2;
11688                                 break;
11689                         case CEE_INITOBJ:
11690                                 CHECK_STACK (1);
11691                                 --sp;
11692                                 CHECK_OPSIZE (6);
11693                                 token = read32 (ip + 2);
11694                                 klass = mini_get_class (method, token, generic_context);
11695                                 CHECK_TYPELOAD (klass);
11696                                 if (generic_class_is_reference_type (cfg, klass))
11697                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11698                                 else
11699                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11700                                 ip += 6;
11701                                 inline_costs += 1;
11702                                 break;
11703                         case CEE_CONSTRAINED_:
11704                                 CHECK_OPSIZE (6);
11705                                 token = read32 (ip + 2);
11706                                 constrained_call = mini_get_class (method, token, generic_context);
11707                                 CHECK_TYPELOAD (constrained_call);
11708                                 ip += 6;
11709                                 break;
11710                         case CEE_CPBLK:
11711                         case CEE_INITBLK: {
11712                                 MonoInst *iargs [3];
11713                                 CHECK_STACK (3);
11714                                 sp -= 3;
11715
11716                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11717                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11718                                 } else if ((ip [1] == CEE_INITBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5) && (sp [1]->opcode == OP_ICONST) && (sp [1]->inst_c0 == 0)) {
11719                                         /* emit_memset only works when val == 0 */
11720                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11721                                 } else {
11722                                         iargs [0] = sp [0];
11723                                         iargs [1] = sp [1];
11724                                         iargs [2] = sp [2];
11725                                         if (ip [1] == CEE_CPBLK) {
11726                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11727                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11728                                         } else {
11729                                                 MonoMethod *memset_method = get_memset_method ();
11730                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11731                                         }
11732                                 }
11733                                 ip += 2;
11734                                 inline_costs += 1;
11735                                 break;
11736                         }
11737                         case CEE_NO_:
11738                                 CHECK_OPSIZE (3);
11739                                 if (ip [2] & 0x1)
11740                                         ins_flag |= MONO_INST_NOTYPECHECK;
11741                                 if (ip [2] & 0x2)
11742                                         ins_flag |= MONO_INST_NORANGECHECK;
11743                                 /* we ignore the no-nullcheck for now since we
11744                                  * really do it explicitly only when doing callvirt->call
11745                                  */
11746                                 ip += 3;
11747                                 break;
11748                         case CEE_RETHROW: {
11749                                 MonoInst *load;
11750                                 int handler_offset = -1;
11751
11752                                 for (i = 0; i < header->num_clauses; ++i) {
11753                                         MonoExceptionClause *clause = &header->clauses [i];
11754                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11755                                                 handler_offset = clause->handler_offset;
11756                                                 break;
11757                                         }
11758                                 }
11759
11760                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11761
11762                                 g_assert (handler_offset != -1);
11763
11764                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11765                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11766                                 ins->sreg1 = load->dreg;
11767                                 MONO_ADD_INS (bblock, ins);
11768
11769                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11770                                 MONO_ADD_INS (bblock, ins);
11771
11772                                 sp = stack_start;
11773                                 link_bblock (cfg, bblock, end_bblock);
11774                                 start_new_bblock = 1;
11775                                 ip += 2;
11776                                 break;
11777                         }
11778                         case CEE_SIZEOF: {
11779                                 guint32 val;
11780                                 int ialign;
11781
11782                                 GSHAREDVT_FAILURE (*ip);
11783
11784                                 CHECK_STACK_OVF (1);
11785                                 CHECK_OPSIZE (6);
11786                                 token = read32 (ip + 2);
11787                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11788                                         MonoType *type = mono_type_create_from_typespec (image, token);
11789                                         val = mono_type_size (type, &ialign);
11790                                 } else {
11791                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11792                                         CHECK_TYPELOAD (klass);
11793                                         mono_class_init (klass);
11794                                         val = mono_type_size (&klass->byval_arg, &ialign);
11795                                 }
11796                                 EMIT_NEW_ICONST (cfg, ins, val);
11797                                 *sp++= ins;
11798                                 ip += 6;
11799                                 break;
11800                         }
11801                         case CEE_REFANYTYPE: {
11802                                 MonoInst *src_var, *src;
11803
11804                                 GSHAREDVT_FAILURE (*ip);
11805
11806                                 CHECK_STACK (1);
11807                                 --sp;
11808
11809                                 // FIXME:
11810                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11811                                 if (!src_var)
11812                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11813                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11814                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
11815                                 *sp++ = ins;
11816                                 ip += 2;
11817                                 break;
11818                         }
11819                         case CEE_READONLY_:
11820                                 readonly = TRUE;
11821                                 ip += 2;
11822                                 break;
11823
11824                         case CEE_UNUSED56:
11825                         case CEE_UNUSED57:
11826                         case CEE_UNUSED70:
11827                         case CEE_UNUSED:
11828                         case CEE_UNUSED99:
11829                                 UNVERIFIED;
11830                                 
11831                         default:
11832                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
11833                                 UNVERIFIED;
11834                         }
11835                         break;
11836                 }
11837                 case CEE_UNUSED58:
11838                 case CEE_UNUSED1:
11839                         UNVERIFIED;
11840
11841                 default:
11842                         g_warning ("opcode 0x%02x not handled", *ip);
11843                         UNVERIFIED;
11844                 }
11845         }
11846         if (start_new_bblock != 1)
11847                 UNVERIFIED;
11848
11849         bblock->cil_length = ip - bblock->cil_code;
11850         if (bblock->next_bb) {
11851                 /* This could already be set because of inlining, #693905 */
11852                 MonoBasicBlock *bb = bblock;
11853
11854                 while (bb->next_bb)
11855                         bb = bb->next_bb;
11856                 bb->next_bb = end_bblock;
11857         } else {
11858                 bblock->next_bb = end_bblock;
11859         }
11860
11861         if (cfg->method == method && cfg->domainvar) {
11862                 MonoInst *store;
11863                 MonoInst *get_domain;
11864
11865                 cfg->cbb = init_localsbb;
11866
11867                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
11868                         MONO_ADD_INS (cfg->cbb, get_domain);
11869                 } else {
11870                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
11871                 }
11872                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
11873                 MONO_ADD_INS (cfg->cbb, store);
11874         }
11875
11876 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
11877         if (cfg->compile_aot)
11878                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
11879                 mono_get_got_var (cfg);
11880 #endif
11881
11882         if (cfg->method == method && cfg->got_var)
11883                 mono_emit_load_got_addr (cfg);
11884
11885         if (init_locals) {
11886                 cfg->cbb = init_localsbb;
11887                 cfg->ip = NULL;
11888                 for (i = 0; i < header->num_locals; ++i) {
11889                         emit_init_local (cfg, i, header->locals [i]);
11890                 }
11891         }
11892
11893         if (cfg->init_ref_vars && cfg->method == method) {
11894                 /* Emit initialization for ref vars */
11895                 // FIXME: Avoid duplication initialization for IL locals.
11896                 for (i = 0; i < cfg->num_varinfo; ++i) {
11897                         MonoInst *ins = cfg->varinfo [i];
11898
11899                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
11900                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
11901                 }
11902         }
11903
11904         if (cfg->lmf_var && cfg->method == method) {
11905                 cfg->cbb = init_localsbb;
11906                 emit_push_lmf (cfg);
11907         }
11908
11909         if (seq_points) {
11910                 MonoBasicBlock *bb;
11911
11912                 /*
11913                  * Make seq points at backward branch targets interruptable.
11914                  */
11915                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
11916                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
11917                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
11918         }
11919
11920         /* Add a sequence point for method entry/exit events */
11921         if (seq_points) {
11922                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
11923                 MONO_ADD_INS (init_localsbb, ins);
11924                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
11925                 MONO_ADD_INS (cfg->bb_exit, ins);
11926         }
11927
11928         /*
11929          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
11930          * the code they refer to was dead (#11880).
11931          */
11932         if (sym_seq_points) {
11933                 for (i = 0; i < header->code_size; ++i) {
11934                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
11935                                 MonoInst *ins;
11936
11937                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
11938                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
11939                         }
11940                 }
11941         }
11942
11943         cfg->ip = NULL;
11944
11945         if (cfg->method == method) {
11946                 MonoBasicBlock *bb;
11947                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11948                         bb->region = mono_find_block_region (cfg, bb->real_offset);
11949                         if (cfg->spvars)
11950                                 mono_create_spvar_for_region (cfg, bb->region);
11951                         if (cfg->verbose_level > 2)
11952                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
11953                 }
11954         }
11955
11956         g_slist_free (class_inits);
11957         dont_inline = g_list_remove (dont_inline, method);
11958
11959         if (inline_costs < 0) {
11960                 char *mname;
11961
11962                 /* Method is too large */
11963                 mname = mono_method_full_name (method, TRUE);
11964                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
11965                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
11966                 g_free (mname);
11967                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11968                 mono_basic_block_free (original_bb);
11969                 return -1;
11970         }
11971
11972         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
11973                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
11974
11975         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11976         mono_basic_block_free (original_bb);
11977         return inline_costs;
11978  
11979  exception_exit:
11980         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
11981         goto cleanup;
11982
11983  inline_failure:
11984         goto cleanup;
11985
11986  load_error:
11987         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
11988         goto cleanup;
11989
11990  unverified:
11991         set_exception_type_from_invalid_il (cfg, method, ip);
11992         goto cleanup;
11993
11994  cleanup:
11995         g_slist_free (class_inits);
11996         mono_basic_block_free (original_bb);
11997         dont_inline = g_list_remove (dont_inline, method);
11998         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11999         return -1;
12000 }
12001
12002 static int
12003 store_membase_reg_to_store_membase_imm (int opcode)
12004 {
12005         switch (opcode) {
12006         case OP_STORE_MEMBASE_REG:
12007                 return OP_STORE_MEMBASE_IMM;
12008         case OP_STOREI1_MEMBASE_REG:
12009                 return OP_STOREI1_MEMBASE_IMM;
12010         case OP_STOREI2_MEMBASE_REG:
12011                 return OP_STOREI2_MEMBASE_IMM;
12012         case OP_STOREI4_MEMBASE_REG:
12013                 return OP_STOREI4_MEMBASE_IMM;
12014         case OP_STOREI8_MEMBASE_REG:
12015                 return OP_STOREI8_MEMBASE_IMM;
12016         default:
12017                 g_assert_not_reached ();
12018         }
12019
12020         return -1;
12021 }               
12022
12023 int
12024 mono_op_to_op_imm (int opcode)
12025 {
12026         switch (opcode) {
12027         case OP_IADD:
12028                 return OP_IADD_IMM;
12029         case OP_ISUB:
12030                 return OP_ISUB_IMM;
12031         case OP_IDIV:
12032                 return OP_IDIV_IMM;
12033         case OP_IDIV_UN:
12034                 return OP_IDIV_UN_IMM;
12035         case OP_IREM:
12036                 return OP_IREM_IMM;
12037         case OP_IREM_UN:
12038                 return OP_IREM_UN_IMM;
12039         case OP_IMUL:
12040                 return OP_IMUL_IMM;
12041         case OP_IAND:
12042                 return OP_IAND_IMM;
12043         case OP_IOR:
12044                 return OP_IOR_IMM;
12045         case OP_IXOR:
12046                 return OP_IXOR_IMM;
12047         case OP_ISHL:
12048                 return OP_ISHL_IMM;
12049         case OP_ISHR:
12050                 return OP_ISHR_IMM;
12051         case OP_ISHR_UN:
12052                 return OP_ISHR_UN_IMM;
12053
12054         case OP_LADD:
12055                 return OP_LADD_IMM;
12056         case OP_LSUB:
12057                 return OP_LSUB_IMM;
12058         case OP_LAND:
12059                 return OP_LAND_IMM;
12060         case OP_LOR:
12061                 return OP_LOR_IMM;
12062         case OP_LXOR:
12063                 return OP_LXOR_IMM;
12064         case OP_LSHL:
12065                 return OP_LSHL_IMM;
12066         case OP_LSHR:
12067                 return OP_LSHR_IMM;
12068         case OP_LSHR_UN:
12069                 return OP_LSHR_UN_IMM;          
12070
12071         case OP_COMPARE:
12072                 return OP_COMPARE_IMM;
12073         case OP_ICOMPARE:
12074                 return OP_ICOMPARE_IMM;
12075         case OP_LCOMPARE:
12076                 return OP_LCOMPARE_IMM;
12077
12078         case OP_STORE_MEMBASE_REG:
12079                 return OP_STORE_MEMBASE_IMM;
12080         case OP_STOREI1_MEMBASE_REG:
12081                 return OP_STOREI1_MEMBASE_IMM;
12082         case OP_STOREI2_MEMBASE_REG:
12083                 return OP_STOREI2_MEMBASE_IMM;
12084         case OP_STOREI4_MEMBASE_REG:
12085                 return OP_STOREI4_MEMBASE_IMM;
12086
12087 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12088         case OP_X86_PUSH:
12089                 return OP_X86_PUSH_IMM;
12090         case OP_X86_COMPARE_MEMBASE_REG:
12091                 return OP_X86_COMPARE_MEMBASE_IMM;
12092 #endif
12093 #if defined(TARGET_AMD64)
12094         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12095                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12096 #endif
12097         case OP_VOIDCALL_REG:
12098                 return OP_VOIDCALL;
12099         case OP_CALL_REG:
12100                 return OP_CALL;
12101         case OP_LCALL_REG:
12102                 return OP_LCALL;
12103         case OP_FCALL_REG:
12104                 return OP_FCALL;
12105         case OP_LOCALLOC:
12106                 return OP_LOCALLOC_IMM;
12107         }
12108
12109         return -1;
12110 }
12111
12112 static int
12113 ldind_to_load_membase (int opcode)
12114 {
12115         switch (opcode) {
12116         case CEE_LDIND_I1:
12117                 return OP_LOADI1_MEMBASE;
12118         case CEE_LDIND_U1:
12119                 return OP_LOADU1_MEMBASE;
12120         case CEE_LDIND_I2:
12121                 return OP_LOADI2_MEMBASE;
12122         case CEE_LDIND_U2:
12123                 return OP_LOADU2_MEMBASE;
12124         case CEE_LDIND_I4:
12125                 return OP_LOADI4_MEMBASE;
12126         case CEE_LDIND_U4:
12127                 return OP_LOADU4_MEMBASE;
12128         case CEE_LDIND_I:
12129                 return OP_LOAD_MEMBASE;
12130         case CEE_LDIND_REF:
12131                 return OP_LOAD_MEMBASE;
12132         case CEE_LDIND_I8:
12133                 return OP_LOADI8_MEMBASE;
12134         case CEE_LDIND_R4:
12135                 return OP_LOADR4_MEMBASE;
12136         case CEE_LDIND_R8:
12137                 return OP_LOADR8_MEMBASE;
12138         default:
12139                 g_assert_not_reached ();
12140         }
12141
12142         return -1;
12143 }
12144
12145 static int
12146 stind_to_store_membase (int opcode)
12147 {
12148         switch (opcode) {
12149         case CEE_STIND_I1:
12150                 return OP_STOREI1_MEMBASE_REG;
12151         case CEE_STIND_I2:
12152                 return OP_STOREI2_MEMBASE_REG;
12153         case CEE_STIND_I4:
12154                 return OP_STOREI4_MEMBASE_REG;
12155         case CEE_STIND_I:
12156         case CEE_STIND_REF:
12157                 return OP_STORE_MEMBASE_REG;
12158         case CEE_STIND_I8:
12159                 return OP_STOREI8_MEMBASE_REG;
12160         case CEE_STIND_R4:
12161                 return OP_STORER4_MEMBASE_REG;
12162         case CEE_STIND_R8:
12163                 return OP_STORER8_MEMBASE_REG;
12164         default:
12165                 g_assert_not_reached ();
12166         }
12167
12168         return -1;
12169 }
12170
12171 int
12172 mono_load_membase_to_load_mem (int opcode)
12173 {
12174         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12175 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12176         switch (opcode) {
12177         case OP_LOAD_MEMBASE:
12178                 return OP_LOAD_MEM;
12179         case OP_LOADU1_MEMBASE:
12180                 return OP_LOADU1_MEM;
12181         case OP_LOADU2_MEMBASE:
12182                 return OP_LOADU2_MEM;
12183         case OP_LOADI4_MEMBASE:
12184                 return OP_LOADI4_MEM;
12185         case OP_LOADU4_MEMBASE:
12186                 return OP_LOADU4_MEM;
12187 #if SIZEOF_REGISTER == 8
12188         case OP_LOADI8_MEMBASE:
12189                 return OP_LOADI8_MEM;
12190 #endif
12191         }
12192 #endif
12193
12194         return -1;
12195 }
12196
12197 static inline int
12198 op_to_op_dest_membase (int store_opcode, int opcode)
12199 {
12200 #if defined(TARGET_X86)
12201         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12202                 return -1;
12203
12204         switch (opcode) {
12205         case OP_IADD:
12206                 return OP_X86_ADD_MEMBASE_REG;
12207         case OP_ISUB:
12208                 return OP_X86_SUB_MEMBASE_REG;
12209         case OP_IAND:
12210                 return OP_X86_AND_MEMBASE_REG;
12211         case OP_IOR:
12212                 return OP_X86_OR_MEMBASE_REG;
12213         case OP_IXOR:
12214                 return OP_X86_XOR_MEMBASE_REG;
12215         case OP_ADD_IMM:
12216         case OP_IADD_IMM:
12217                 return OP_X86_ADD_MEMBASE_IMM;
12218         case OP_SUB_IMM:
12219         case OP_ISUB_IMM:
12220                 return OP_X86_SUB_MEMBASE_IMM;
12221         case OP_AND_IMM:
12222         case OP_IAND_IMM:
12223                 return OP_X86_AND_MEMBASE_IMM;
12224         case OP_OR_IMM:
12225         case OP_IOR_IMM:
12226                 return OP_X86_OR_MEMBASE_IMM;
12227         case OP_XOR_IMM:
12228         case OP_IXOR_IMM:
12229                 return OP_X86_XOR_MEMBASE_IMM;
12230         case OP_MOVE:
12231                 return OP_NOP;
12232         }
12233 #endif
12234
12235 #if defined(TARGET_AMD64)
12236         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12237                 return -1;
12238
12239         switch (opcode) {
12240         case OP_IADD:
12241                 return OP_X86_ADD_MEMBASE_REG;
12242         case OP_ISUB:
12243                 return OP_X86_SUB_MEMBASE_REG;
12244         case OP_IAND:
12245                 return OP_X86_AND_MEMBASE_REG;
12246         case OP_IOR:
12247                 return OP_X86_OR_MEMBASE_REG;
12248         case OP_IXOR:
12249                 return OP_X86_XOR_MEMBASE_REG;
12250         case OP_IADD_IMM:
12251                 return OP_X86_ADD_MEMBASE_IMM;
12252         case OP_ISUB_IMM:
12253                 return OP_X86_SUB_MEMBASE_IMM;
12254         case OP_IAND_IMM:
12255                 return OP_X86_AND_MEMBASE_IMM;
12256         case OP_IOR_IMM:
12257                 return OP_X86_OR_MEMBASE_IMM;
12258         case OP_IXOR_IMM:
12259                 return OP_X86_XOR_MEMBASE_IMM;
12260         case OP_LADD:
12261                 return OP_AMD64_ADD_MEMBASE_REG;
12262         case OP_LSUB:
12263                 return OP_AMD64_SUB_MEMBASE_REG;
12264         case OP_LAND:
12265                 return OP_AMD64_AND_MEMBASE_REG;
12266         case OP_LOR:
12267                 return OP_AMD64_OR_MEMBASE_REG;
12268         case OP_LXOR:
12269                 return OP_AMD64_XOR_MEMBASE_REG;
12270         case OP_ADD_IMM:
12271         case OP_LADD_IMM:
12272                 return OP_AMD64_ADD_MEMBASE_IMM;
12273         case OP_SUB_IMM:
12274         case OP_LSUB_IMM:
12275                 return OP_AMD64_SUB_MEMBASE_IMM;
12276         case OP_AND_IMM:
12277         case OP_LAND_IMM:
12278                 return OP_AMD64_AND_MEMBASE_IMM;
12279         case OP_OR_IMM:
12280         case OP_LOR_IMM:
12281                 return OP_AMD64_OR_MEMBASE_IMM;
12282         case OP_XOR_IMM:
12283         case OP_LXOR_IMM:
12284                 return OP_AMD64_XOR_MEMBASE_IMM;
12285         case OP_MOVE:
12286                 return OP_NOP;
12287         }
12288 #endif
12289
12290         return -1;
12291 }
12292
12293 static inline int
12294 op_to_op_store_membase (int store_opcode, int opcode)
12295 {
12296 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12297         switch (opcode) {
12298         case OP_ICEQ:
12299                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12300                         return OP_X86_SETEQ_MEMBASE;
12301         case OP_CNE:
12302                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12303                         return OP_X86_SETNE_MEMBASE;
12304         }
12305 #endif
12306
12307         return -1;
12308 }
12309
12310 static inline int
12311 op_to_op_src1_membase (int load_opcode, int opcode)
12312 {
12313 #ifdef TARGET_X86
12314         /* FIXME: This has sign extension issues */
12315         /*
12316         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12317                 return OP_X86_COMPARE_MEMBASE8_IMM;
12318         */
12319
12320         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12321                 return -1;
12322
12323         switch (opcode) {
12324         case OP_X86_PUSH:
12325                 return OP_X86_PUSH_MEMBASE;
12326         case OP_COMPARE_IMM:
12327         case OP_ICOMPARE_IMM:
12328                 return OP_X86_COMPARE_MEMBASE_IMM;
12329         case OP_COMPARE:
12330         case OP_ICOMPARE:
12331                 return OP_X86_COMPARE_MEMBASE_REG;
12332         }
12333 #endif
12334
12335 #ifdef TARGET_AMD64
12336         /* FIXME: This has sign extension issues */
12337         /*
12338         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12339                 return OP_X86_COMPARE_MEMBASE8_IMM;
12340         */
12341
12342         switch (opcode) {
12343         case OP_X86_PUSH:
12344 #ifdef __mono_ilp32__
12345                 if (load_opcode == OP_LOADI8_MEMBASE)
12346 #else
12347                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12348 #endif
12349                         return OP_X86_PUSH_MEMBASE;
12350                 break;
12351                 /* FIXME: This only works for 32 bit immediates
12352         case OP_COMPARE_IMM:
12353         case OP_LCOMPARE_IMM:
12354                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12355                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12356                 */
12357         case OP_ICOMPARE_IMM:
12358                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12359                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12360                 break;
12361         case OP_COMPARE:
12362         case OP_LCOMPARE:
12363 #ifdef __mono_ilp32__
12364                 if (load_opcode == OP_LOAD_MEMBASE)
12365                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12366                 if (load_opcode == OP_LOADI8_MEMBASE)
12367 #else
12368                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12369 #endif
12370                         return OP_AMD64_COMPARE_MEMBASE_REG;
12371                 break;
12372         case OP_ICOMPARE:
12373                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12374                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12375                 break;
12376         }
12377 #endif
12378
12379         return -1;
12380 }
12381
12382 static inline int
12383 op_to_op_src2_membase (int load_opcode, int opcode)
12384 {
12385 #ifdef TARGET_X86
12386         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12387                 return -1;
12388         
12389         switch (opcode) {
12390         case OP_COMPARE:
12391         case OP_ICOMPARE:
12392                 return OP_X86_COMPARE_REG_MEMBASE;
12393         case OP_IADD:
12394                 return OP_X86_ADD_REG_MEMBASE;
12395         case OP_ISUB:
12396                 return OP_X86_SUB_REG_MEMBASE;
12397         case OP_IAND:
12398                 return OP_X86_AND_REG_MEMBASE;
12399         case OP_IOR:
12400                 return OP_X86_OR_REG_MEMBASE;
12401         case OP_IXOR:
12402                 return OP_X86_XOR_REG_MEMBASE;
12403         }
12404 #endif
12405
12406 #ifdef TARGET_AMD64
12407 #ifdef __mono_ilp32__
12408         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12409 #else
12410         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12411 #endif
12412                 switch (opcode) {
12413                 case OP_ICOMPARE:
12414                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12415                 case OP_IADD:
12416                         return OP_X86_ADD_REG_MEMBASE;
12417                 case OP_ISUB:
12418                         return OP_X86_SUB_REG_MEMBASE;
12419                 case OP_IAND:
12420                         return OP_X86_AND_REG_MEMBASE;
12421                 case OP_IOR:
12422                         return OP_X86_OR_REG_MEMBASE;
12423                 case OP_IXOR:
12424                         return OP_X86_XOR_REG_MEMBASE;
12425                 }
12426 #ifdef __mono_ilp32__
12427         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12428 #else
12429         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12430 #endif
12431                 switch (opcode) {
12432                 case OP_COMPARE:
12433                 case OP_LCOMPARE:
12434                         return OP_AMD64_COMPARE_REG_MEMBASE;
12435                 case OP_LADD:
12436                         return OP_AMD64_ADD_REG_MEMBASE;
12437                 case OP_LSUB:
12438                         return OP_AMD64_SUB_REG_MEMBASE;
12439                 case OP_LAND:
12440                         return OP_AMD64_AND_REG_MEMBASE;
12441                 case OP_LOR:
12442                         return OP_AMD64_OR_REG_MEMBASE;
12443                 case OP_LXOR:
12444                         return OP_AMD64_XOR_REG_MEMBASE;
12445                 }
12446         }
12447 #endif
12448
12449         return -1;
12450 }
12451
12452 int
12453 mono_op_to_op_imm_noemul (int opcode)
12454 {
12455         switch (opcode) {
12456 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12457         case OP_LSHR:
12458         case OP_LSHL:
12459         case OP_LSHR_UN:
12460                 return -1;
12461 #endif
12462 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12463         case OP_IDIV:
12464         case OP_IDIV_UN:
12465         case OP_IREM:
12466         case OP_IREM_UN:
12467                 return -1;
12468 #endif
12469 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12470         case OP_IMUL:
12471                 return -1;
12472 #endif
12473         default:
12474                 return mono_op_to_op_imm (opcode);
12475         }
12476 }
12477
12478 /**
12479  * mono_handle_global_vregs:
12480  *
12481  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12482  * for them.
12483  */
12484 void
12485 mono_handle_global_vregs (MonoCompile *cfg)
12486 {
12487         gint32 *vreg_to_bb;
12488         MonoBasicBlock *bb;
12489         int i, pos;
12490
12491         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12492
12493 #ifdef MONO_ARCH_SIMD_INTRINSICS
12494         if (cfg->uses_simd_intrinsics)
12495                 mono_simd_simplify_indirection (cfg);
12496 #endif
12497
12498         /* Find local vregs used in more than one bb */
12499         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12500                 MonoInst *ins = bb->code;       
12501                 int block_num = bb->block_num;
12502
12503                 if (cfg->verbose_level > 2)
12504                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12505
12506                 cfg->cbb = bb;
12507                 for (; ins; ins = ins->next) {
12508                         const char *spec = INS_INFO (ins->opcode);
12509                         int regtype = 0, regindex;
12510                         gint32 prev_bb;
12511
12512                         if (G_UNLIKELY (cfg->verbose_level > 2))
12513                                 mono_print_ins (ins);
12514
12515                         g_assert (ins->opcode >= MONO_CEE_LAST);
12516
12517                         for (regindex = 0; regindex < 4; regindex ++) {
12518                                 int vreg = 0;
12519
12520                                 if (regindex == 0) {
12521                                         regtype = spec [MONO_INST_DEST];
12522                                         if (regtype == ' ')
12523                                                 continue;
12524                                         vreg = ins->dreg;
12525                                 } else if (regindex == 1) {
12526                                         regtype = spec [MONO_INST_SRC1];
12527                                         if (regtype == ' ')
12528                                                 continue;
12529                                         vreg = ins->sreg1;
12530                                 } else if (regindex == 2) {
12531                                         regtype = spec [MONO_INST_SRC2];
12532                                         if (regtype == ' ')
12533                                                 continue;
12534                                         vreg = ins->sreg2;
12535                                 } else if (regindex == 3) {
12536                                         regtype = spec [MONO_INST_SRC3];
12537                                         if (regtype == ' ')
12538                                                 continue;
12539                                         vreg = ins->sreg3;
12540                                 }
12541
12542 #if SIZEOF_REGISTER == 4
12543                                 /* In the LLVM case, the long opcodes are not decomposed */
12544                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12545                                         /*
12546                                          * Since some instructions reference the original long vreg,
12547                                          * and some reference the two component vregs, it is quite hard
12548                                          * to determine when it needs to be global. So be conservative.
12549                                          */
12550                                         if (!get_vreg_to_inst (cfg, vreg)) {
12551                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12552
12553                                                 if (cfg->verbose_level > 2)
12554                                                         printf ("LONG VREG R%d made global.\n", vreg);
12555                                         }
12556
12557                                         /*
12558                                          * Make the component vregs volatile since the optimizations can
12559                                          * get confused otherwise.
12560                                          */
12561                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12562                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12563                                 }
12564 #endif
12565
12566                                 g_assert (vreg != -1);
12567
12568                                 prev_bb = vreg_to_bb [vreg];
12569                                 if (prev_bb == 0) {
12570                                         /* 0 is a valid block num */
12571                                         vreg_to_bb [vreg] = block_num + 1;
12572                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12573                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12574                                                 continue;
12575
12576                                         if (!get_vreg_to_inst (cfg, vreg)) {
12577                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12578                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12579
12580                                                 switch (regtype) {
12581                                                 case 'i':
12582                                                         if (vreg_is_ref (cfg, vreg))
12583                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12584                                                         else
12585                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12586                                                         break;
12587                                                 case 'l':
12588                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12589                                                         break;
12590                                                 case 'f':
12591                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12592                                                         break;
12593                                                 case 'v':
12594                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12595                                                         break;
12596                                                 default:
12597                                                         g_assert_not_reached ();
12598                                                 }
12599                                         }
12600
12601                                         /* Flag as having been used in more than one bb */
12602                                         vreg_to_bb [vreg] = -1;
12603                                 }
12604                         }
12605                 }
12606         }
12607
12608         /* If a variable is used in only one bblock, convert it into a local vreg */
12609         for (i = 0; i < cfg->num_varinfo; i++) {
12610                 MonoInst *var = cfg->varinfo [i];
12611                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12612
12613                 switch (var->type) {
12614                 case STACK_I4:
12615                 case STACK_OBJ:
12616                 case STACK_PTR:
12617                 case STACK_MP:
12618                 case STACK_VTYPE:
12619 #if SIZEOF_REGISTER == 8
12620                 case STACK_I8:
12621 #endif
12622 #if !defined(TARGET_X86)
12623                 /* Enabling this screws up the fp stack on x86 */
12624                 case STACK_R8:
12625 #endif
12626                         if (mono_arch_is_soft_float ())
12627                                 break;
12628
12629                         /* Arguments are implicitly global */
12630                         /* Putting R4 vars into registers doesn't work currently */
12631                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12632                         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) {
12633                                 /* 
12634                                  * Make that the variable's liveness interval doesn't contain a call, since
12635                                  * that would cause the lvreg to be spilled, making the whole optimization
12636                                  * useless.
12637                                  */
12638                                 /* This is too slow for JIT compilation */
12639 #if 0
12640                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12641                                         MonoInst *ins;
12642                                         int def_index, call_index, ins_index;
12643                                         gboolean spilled = FALSE;
12644
12645                                         def_index = -1;
12646                                         call_index = -1;
12647                                         ins_index = 0;
12648                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12649                                                 const char *spec = INS_INFO (ins->opcode);
12650
12651                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12652                                                         def_index = ins_index;
12653
12654                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12655                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12656                                                         if (call_index > def_index) {
12657                                                                 spilled = TRUE;
12658                                                                 break;
12659                                                         }
12660                                                 }
12661
12662                                                 if (MONO_IS_CALL (ins))
12663                                                         call_index = ins_index;
12664
12665                                                 ins_index ++;
12666                                         }
12667
12668                                         if (spilled)
12669                                                 break;
12670                                 }
12671 #endif
12672
12673                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12674                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12675                                 var->flags |= MONO_INST_IS_DEAD;
12676                                 cfg->vreg_to_inst [var->dreg] = NULL;
12677                         }
12678                         break;
12679                 }
12680         }
12681
12682         /* 
12683          * Compress the varinfo and vars tables so the liveness computation is faster and
12684          * takes up less space.
12685          */
12686         pos = 0;
12687         for (i = 0; i < cfg->num_varinfo; ++i) {
12688                 MonoInst *var = cfg->varinfo [i];
12689                 if (pos < i && cfg->locals_start == i)
12690                         cfg->locals_start = pos;
12691                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12692                         if (pos < i) {
12693                                 cfg->varinfo [pos] = cfg->varinfo [i];
12694                                 cfg->varinfo [pos]->inst_c0 = pos;
12695                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12696                                 cfg->vars [pos].idx = pos;
12697 #if SIZEOF_REGISTER == 4
12698                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12699                                         /* Modify the two component vars too */
12700                                         MonoInst *var1;
12701
12702                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12703                                         var1->inst_c0 = pos;
12704                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12705                                         var1->inst_c0 = pos;
12706                                 }
12707 #endif
12708                         }
12709                         pos ++;
12710                 }
12711         }
12712         cfg->num_varinfo = pos;
12713         if (cfg->locals_start > cfg->num_varinfo)
12714                 cfg->locals_start = cfg->num_varinfo;
12715 }
12716
12717 /**
12718  * mono_spill_global_vars:
12719  *
12720  *   Generate spill code for variables which are not allocated to registers, 
12721  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12722  * code is generated which could be optimized by the local optimization passes.
12723  */
12724 void
12725 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12726 {
12727         MonoBasicBlock *bb;
12728         char spec2 [16];
12729         int orig_next_vreg;
12730         guint32 *vreg_to_lvreg;
12731         guint32 *lvregs;
12732         guint32 i, lvregs_len;
12733         gboolean dest_has_lvreg = FALSE;
12734         guint32 stacktypes [128];
12735         MonoInst **live_range_start, **live_range_end;
12736         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12737         int *gsharedvt_vreg_to_idx = NULL;
12738
12739         *need_local_opts = FALSE;
12740
12741         memset (spec2, 0, sizeof (spec2));
12742
12743         /* FIXME: Move this function to mini.c */
12744         stacktypes ['i'] = STACK_PTR;
12745         stacktypes ['l'] = STACK_I8;
12746         stacktypes ['f'] = STACK_R8;
12747 #ifdef MONO_ARCH_SIMD_INTRINSICS
12748         stacktypes ['x'] = STACK_VTYPE;
12749 #endif
12750
12751 #if SIZEOF_REGISTER == 4
12752         /* Create MonoInsts for longs */
12753         for (i = 0; i < cfg->num_varinfo; i++) {
12754                 MonoInst *ins = cfg->varinfo [i];
12755
12756                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12757                         switch (ins->type) {
12758                         case STACK_R8:
12759                         case STACK_I8: {
12760                                 MonoInst *tree;
12761
12762                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12763                                         break;
12764
12765                                 g_assert (ins->opcode == OP_REGOFFSET);
12766
12767                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12768                                 g_assert (tree);
12769                                 tree->opcode = OP_REGOFFSET;
12770                                 tree->inst_basereg = ins->inst_basereg;
12771                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12772
12773                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12774                                 g_assert (tree);
12775                                 tree->opcode = OP_REGOFFSET;
12776                                 tree->inst_basereg = ins->inst_basereg;
12777                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12778                                 break;
12779                         }
12780                         default:
12781                                 break;
12782                         }
12783                 }
12784         }
12785 #endif
12786
12787         if (cfg->compute_gc_maps) {
12788                 /* registers need liveness info even for !non refs */
12789                 for (i = 0; i < cfg->num_varinfo; i++) {
12790                         MonoInst *ins = cfg->varinfo [i];
12791
12792                         if (ins->opcode == OP_REGVAR)
12793                                 ins->flags |= MONO_INST_GC_TRACK;
12794                 }
12795         }
12796
12797         if (cfg->gsharedvt) {
12798                 gsharedvt_vreg_to_idx = g_new0 (int, cfg->next_vreg);
12799
12800                 for (i = 0; i < cfg->num_varinfo; ++i) {
12801                         MonoInst *ins = cfg->varinfo [i];
12802                         int idx;
12803
12804                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12805                                 if (i >= cfg->locals_start) {
12806                                         /* Local */
12807                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
12808                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
12809                                         ins->opcode = OP_GSHAREDVT_LOCAL;
12810                                         ins->inst_imm = idx;
12811                                 } else {
12812                                         /* Arg */
12813                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
12814                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
12815                                 }
12816                         }
12817                 }
12818         }
12819                 
12820         /* FIXME: widening and truncation */
12821
12822         /*
12823          * As an optimization, when a variable allocated to the stack is first loaded into 
12824          * an lvreg, we will remember the lvreg and use it the next time instead of loading
12825          * the variable again.
12826          */
12827         orig_next_vreg = cfg->next_vreg;
12828         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
12829         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
12830         lvregs_len = 0;
12831
12832         /* 
12833          * These arrays contain the first and last instructions accessing a given
12834          * variable.
12835          * Since we emit bblocks in the same order we process them here, and we
12836          * don't split live ranges, these will precisely describe the live range of
12837          * the variable, i.e. the instruction range where a valid value can be found
12838          * in the variables location.
12839          * The live range is computed using the liveness info computed by the liveness pass.
12840          * We can't use vmv->range, since that is an abstract live range, and we need
12841          * one which is instruction precise.
12842          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
12843          */
12844         /* FIXME: Only do this if debugging info is requested */
12845         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
12846         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
12847         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12848         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12849         
12850         /* Add spill loads/stores */
12851         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12852                 MonoInst *ins;
12853
12854                 if (cfg->verbose_level > 2)
12855                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
12856
12857                 /* Clear vreg_to_lvreg array */
12858                 for (i = 0; i < lvregs_len; i++)
12859                         vreg_to_lvreg [lvregs [i]] = 0;
12860                 lvregs_len = 0;
12861
12862                 cfg->cbb = bb;
12863                 MONO_BB_FOR_EACH_INS (bb, ins) {
12864                         const char *spec = INS_INFO (ins->opcode);
12865                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
12866                         gboolean store, no_lvreg;
12867                         int sregs [MONO_MAX_SRC_REGS];
12868
12869                         if (G_UNLIKELY (cfg->verbose_level > 2))
12870                                 mono_print_ins (ins);
12871
12872                         if (ins->opcode == OP_NOP)
12873                                 continue;
12874
12875                         /* 
12876                          * We handle LDADDR here as well, since it can only be decomposed
12877                          * when variable addresses are known.
12878                          */
12879                         if (ins->opcode == OP_LDADDR) {
12880                                 MonoInst *var = ins->inst_p0;
12881
12882                                 if (var->opcode == OP_VTARG_ADDR) {
12883                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
12884                                         MonoInst *vtaddr = var->inst_left;
12885                                         if (vtaddr->opcode == OP_REGVAR) {
12886                                                 ins->opcode = OP_MOVE;
12887                                                 ins->sreg1 = vtaddr->dreg;
12888                                         }
12889                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
12890                                                 ins->opcode = OP_LOAD_MEMBASE;
12891                                                 ins->inst_basereg = vtaddr->inst_basereg;
12892                                                 ins->inst_offset = vtaddr->inst_offset;
12893                                         } else
12894                                                 NOT_IMPLEMENTED;
12895                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
12896                                         /* gsharedvt arg passed by ref */
12897                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
12898
12899                                         ins->opcode = OP_LOAD_MEMBASE;
12900                                         ins->inst_basereg = var->inst_basereg;
12901                                         ins->inst_offset = var->inst_offset;
12902                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
12903                                         MonoInst *load, *load2, *load3;
12904                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
12905                                         int reg1, reg2, reg3;
12906                                         MonoInst *info_var = cfg->gsharedvt_info_var;
12907                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
12908
12909                                         /*
12910                                          * gsharedvt local.
12911                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
12912                                          */
12913
12914                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
12915
12916                                         g_assert (info_var);
12917                                         g_assert (locals_var);
12918
12919                                         /* Mark the instruction used to compute the locals var as used */
12920                                         cfg->gsharedvt_locals_var_ins = NULL;
12921
12922                                         /* Load the offset */
12923                                         if (info_var->opcode == OP_REGOFFSET) {
12924                                                 reg1 = alloc_ireg (cfg);
12925                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
12926                                         } else if (info_var->opcode == OP_REGVAR) {
12927                                                 load = NULL;
12928                                                 reg1 = info_var->dreg;
12929                                         } else {
12930                                                 g_assert_not_reached ();
12931                                         }
12932                                         reg2 = alloc_ireg (cfg);
12933                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
12934                                         /* Load the locals area address */
12935                                         reg3 = alloc_ireg (cfg);
12936                                         if (locals_var->opcode == OP_REGOFFSET) {
12937                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
12938                                         } else if (locals_var->opcode == OP_REGVAR) {
12939                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
12940                                         } else {
12941                                                 g_assert_not_reached ();
12942                                         }
12943                                         /* Compute the address */
12944                                         ins->opcode = OP_PADD;
12945                                         ins->sreg1 = reg3;
12946                                         ins->sreg2 = reg2;
12947
12948                                         mono_bblock_insert_before_ins (bb, ins, load3);
12949                                         mono_bblock_insert_before_ins (bb, load3, load2);
12950                                         if (load)
12951                                                 mono_bblock_insert_before_ins (bb, load2, load);
12952                                 } else {
12953                                         g_assert (var->opcode == OP_REGOFFSET);
12954
12955                                         ins->opcode = OP_ADD_IMM;
12956                                         ins->sreg1 = var->inst_basereg;
12957                                         ins->inst_imm = var->inst_offset;
12958                                 }
12959
12960                                 *need_local_opts = TRUE;
12961                                 spec = INS_INFO (ins->opcode);
12962                         }
12963
12964                         if (ins->opcode < MONO_CEE_LAST) {
12965                                 mono_print_ins (ins);
12966                                 g_assert_not_reached ();
12967                         }
12968
12969                         /*
12970                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
12971                          * src register.
12972                          * FIXME:
12973                          */
12974                         if (MONO_IS_STORE_MEMBASE (ins)) {
12975                                 tmp_reg = ins->dreg;
12976                                 ins->dreg = ins->sreg2;
12977                                 ins->sreg2 = tmp_reg;
12978                                 store = TRUE;
12979
12980                                 spec2 [MONO_INST_DEST] = ' ';
12981                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
12982                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
12983                                 spec2 [MONO_INST_SRC3] = ' ';
12984                                 spec = spec2;
12985                         } else if (MONO_IS_STORE_MEMINDEX (ins))
12986                                 g_assert_not_reached ();
12987                         else
12988                                 store = FALSE;
12989                         no_lvreg = FALSE;
12990
12991                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
12992                                 printf ("\t %.3s %d", spec, ins->dreg);
12993                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
12994                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
12995                                         printf (" %d", sregs [srcindex]);
12996                                 printf ("\n");
12997                         }
12998
12999                         /***************/
13000                         /*    DREG     */
13001                         /***************/
13002                         regtype = spec [MONO_INST_DEST];
13003                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13004                         prev_dreg = -1;
13005
13006                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13007                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13008                                 MonoInst *store_ins;
13009                                 int store_opcode;
13010                                 MonoInst *def_ins = ins;
13011                                 int dreg = ins->dreg; /* The original vreg */
13012
13013                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13014
13015                                 if (var->opcode == OP_REGVAR) {
13016                                         ins->dreg = var->dreg;
13017                                 } 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)) {
13018                                         /* 
13019                                          * Instead of emitting a load+store, use a _membase opcode.
13020                                          */
13021                                         g_assert (var->opcode == OP_REGOFFSET);
13022                                         if (ins->opcode == OP_MOVE) {
13023                                                 NULLIFY_INS (ins);
13024                                                 def_ins = NULL;
13025                                         } else {
13026                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13027                                                 ins->inst_basereg = var->inst_basereg;
13028                                                 ins->inst_offset = var->inst_offset;
13029                                                 ins->dreg = -1;
13030                                         }
13031                                         spec = INS_INFO (ins->opcode);
13032                                 } else {
13033                                         guint32 lvreg;
13034
13035                                         g_assert (var->opcode == OP_REGOFFSET);
13036
13037                                         prev_dreg = ins->dreg;
13038
13039                                         /* Invalidate any previous lvreg for this vreg */
13040                                         vreg_to_lvreg [ins->dreg] = 0;
13041
13042                                         lvreg = 0;
13043
13044                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13045                                                 regtype = 'l';
13046                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13047                                         }
13048
13049                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13050
13051 #if SIZEOF_REGISTER != 8
13052                                         if (regtype == 'l') {
13053                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13054                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13055                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13056                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13057                                                 def_ins = store_ins;
13058                                         }
13059                                         else
13060 #endif
13061                                         {
13062                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13063
13064                                                 /* Try to fuse the store into the instruction itself */
13065                                                 /* FIXME: Add more instructions */
13066                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13067                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13068                                                         ins->inst_imm = ins->inst_c0;
13069                                                         ins->inst_destbasereg = var->inst_basereg;
13070                                                         ins->inst_offset = var->inst_offset;
13071                                                         spec = INS_INFO (ins->opcode);
13072                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13073                                                         ins->opcode = store_opcode;
13074                                                         ins->inst_destbasereg = var->inst_basereg;
13075                                                         ins->inst_offset = var->inst_offset;
13076
13077                                                         no_lvreg = TRUE;
13078
13079                                                         tmp_reg = ins->dreg;
13080                                                         ins->dreg = ins->sreg2;
13081                                                         ins->sreg2 = tmp_reg;
13082                                                         store = TRUE;
13083
13084                                                         spec2 [MONO_INST_DEST] = ' ';
13085                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13086                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13087                                                         spec2 [MONO_INST_SRC3] = ' ';
13088                                                         spec = spec2;
13089                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13090                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13091                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13092                                                         ins->dreg = -1;
13093                                                         ins->inst_basereg = var->inst_basereg;
13094                                                         ins->inst_offset = var->inst_offset;
13095                                                         spec = INS_INFO (ins->opcode);
13096                                                 } else {
13097                                                         /* printf ("INS: "); mono_print_ins (ins); */
13098                                                         /* Create a store instruction */
13099                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13100
13101                                                         /* Insert it after the instruction */
13102                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13103
13104                                                         def_ins = store_ins;
13105
13106                                                         /* 
13107                                                          * We can't assign ins->dreg to var->dreg here, since the
13108                                                          * sregs could use it. So set a flag, and do it after
13109                                                          * the sregs.
13110                                                          */
13111                                                         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)))
13112                                                                 dest_has_lvreg = TRUE;
13113                                                 }
13114                                         }
13115                                 }
13116
13117                                 if (def_ins && !live_range_start [dreg]) {
13118                                         live_range_start [dreg] = def_ins;
13119                                         live_range_start_bb [dreg] = bb;
13120                                 }
13121
13122                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13123                                         MonoInst *tmp;
13124
13125                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13126                                         tmp->inst_c1 = dreg;
13127                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13128                                 }
13129                         }
13130
13131                         /************/
13132                         /*  SREGS   */
13133                         /************/
13134                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13135                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13136                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13137                                 sreg = sregs [srcindex];
13138
13139                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13140                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13141                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13142                                         MonoInst *use_ins = ins;
13143                                         MonoInst *load_ins;
13144                                         guint32 load_opcode;
13145
13146                                         if (var->opcode == OP_REGVAR) {
13147                                                 sregs [srcindex] = var->dreg;
13148                                                 //mono_inst_set_src_registers (ins, sregs);
13149                                                 live_range_end [sreg] = use_ins;
13150                                                 live_range_end_bb [sreg] = bb;
13151
13152                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13153                                                         MonoInst *tmp;
13154
13155                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13156                                                         /* var->dreg is a hreg */
13157                                                         tmp->inst_c1 = sreg;
13158                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13159                                                 }
13160
13161                                                 continue;
13162                                         }
13163
13164                                         g_assert (var->opcode == OP_REGOFFSET);
13165                                                 
13166                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13167
13168                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13169
13170                                         if (vreg_to_lvreg [sreg]) {
13171                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13172
13173                                                 /* The variable is already loaded to an lvreg */
13174                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13175                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13176                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13177                                                 //mono_inst_set_src_registers (ins, sregs);
13178                                                 continue;
13179                                         }
13180
13181                                         /* Try to fuse the load into the instruction */
13182                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13183                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13184                                                 sregs [0] = var->inst_basereg;
13185                                                 //mono_inst_set_src_registers (ins, sregs);
13186                                                 ins->inst_offset = var->inst_offset;
13187                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13188                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13189                                                 sregs [1] = var->inst_basereg;
13190                                                 //mono_inst_set_src_registers (ins, sregs);
13191                                                 ins->inst_offset = var->inst_offset;
13192                                         } else {
13193                                                 if (MONO_IS_REAL_MOVE (ins)) {
13194                                                         ins->opcode = OP_NOP;
13195                                                         sreg = ins->dreg;
13196                                                 } else {
13197                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13198
13199                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13200
13201                                                         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) {
13202                                                                 if (var->dreg == prev_dreg) {
13203                                                                         /*
13204                                                                          * sreg refers to the value loaded by the load
13205                                                                          * emitted below, but we need to use ins->dreg
13206                                                                          * since it refers to the store emitted earlier.
13207                                                                          */
13208                                                                         sreg = ins->dreg;
13209                                                                 }
13210                                                                 g_assert (sreg != -1);
13211                                                                 vreg_to_lvreg [var->dreg] = sreg;
13212                                                                 g_assert (lvregs_len < 1024);
13213                                                                 lvregs [lvregs_len ++] = var->dreg;
13214                                                         }
13215                                                 }
13216
13217                                                 sregs [srcindex] = sreg;
13218                                                 //mono_inst_set_src_registers (ins, sregs);
13219
13220 #if SIZEOF_REGISTER != 8
13221                                                 if (regtype == 'l') {
13222                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13223                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13224                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13225                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13226                                                         use_ins = load_ins;
13227                                                 }
13228                                                 else
13229 #endif
13230                                                 {
13231 #if SIZEOF_REGISTER == 4
13232                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13233 #endif
13234                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13235                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13236                                                         use_ins = load_ins;
13237                                                 }
13238                                         }
13239
13240                                         if (var->dreg < orig_next_vreg) {
13241                                                 live_range_end [var->dreg] = use_ins;
13242                                                 live_range_end_bb [var->dreg] = bb;
13243                                         }
13244
13245                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13246                                                 MonoInst *tmp;
13247
13248                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13249                                                 tmp->inst_c1 = var->dreg;
13250                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13251                                         }
13252                                 }
13253                         }
13254                         mono_inst_set_src_registers (ins, sregs);
13255
13256                         if (dest_has_lvreg) {
13257                                 g_assert (ins->dreg != -1);
13258                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13259                                 g_assert (lvregs_len < 1024);
13260                                 lvregs [lvregs_len ++] = prev_dreg;
13261                                 dest_has_lvreg = FALSE;
13262                         }
13263
13264                         if (store) {
13265                                 tmp_reg = ins->dreg;
13266                                 ins->dreg = ins->sreg2;
13267                                 ins->sreg2 = tmp_reg;
13268                         }
13269
13270                         if (MONO_IS_CALL (ins)) {
13271                                 /* Clear vreg_to_lvreg array */
13272                                 for (i = 0; i < lvregs_len; i++)
13273                                         vreg_to_lvreg [lvregs [i]] = 0;
13274                                 lvregs_len = 0;
13275                         } else if (ins->opcode == OP_NOP) {
13276                                 ins->dreg = -1;
13277                                 MONO_INST_NULLIFY_SREGS (ins);
13278                         }
13279
13280                         if (cfg->verbose_level > 2)
13281                                 mono_print_ins_index (1, ins);
13282                 }
13283
13284                 /* Extend the live range based on the liveness info */
13285                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13286                         for (i = 0; i < cfg->num_varinfo; i ++) {
13287                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13288
13289                                 if (vreg_is_volatile (cfg, vi->vreg))
13290                                         /* The liveness info is incomplete */
13291                                         continue;
13292
13293                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13294                                         /* Live from at least the first ins of this bb */
13295                                         live_range_start [vi->vreg] = bb->code;
13296                                         live_range_start_bb [vi->vreg] = bb;
13297                                 }
13298
13299                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13300                                         /* Live at least until the last ins of this bb */
13301                                         live_range_end [vi->vreg] = bb->last_ins;
13302                                         live_range_end_bb [vi->vreg] = bb;
13303                                 }
13304                         }
13305                 }
13306         }
13307         
13308 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13309         /*
13310          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13311          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13312          */
13313         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13314                 for (i = 0; i < cfg->num_varinfo; ++i) {
13315                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13316                         MonoInst *ins;
13317
13318                         if (live_range_start [vreg]) {
13319                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13320                                 ins->inst_c0 = i;
13321                                 ins->inst_c1 = vreg;
13322                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13323                         }
13324                         if (live_range_end [vreg]) {
13325                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13326                                 ins->inst_c0 = i;
13327                                 ins->inst_c1 = vreg;
13328                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13329                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13330                                 else
13331                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13332                         }
13333                 }
13334         }
13335 #endif
13336
13337         if (cfg->gsharedvt_locals_var_ins) {
13338                 /* Nullify if unused */
13339                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13340                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13341         }
13342
13343         g_free (live_range_start);
13344         g_free (live_range_end);
13345         g_free (live_range_start_bb);
13346         g_free (live_range_end_bb);
13347 }
13348
13349 /**
13350  * FIXME:
13351  * - use 'iadd' instead of 'int_add'
13352  * - handling ovf opcodes: decompose in method_to_ir.
13353  * - unify iregs/fregs
13354  *   -> partly done, the missing parts are:
13355  *   - a more complete unification would involve unifying the hregs as well, so
13356  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13357  *     would no longer map to the machine hregs, so the code generators would need to
13358  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13359  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13360  *     fp/non-fp branches speeds it up by about 15%.
13361  * - use sext/zext opcodes instead of shifts
13362  * - add OP_ICALL
13363  * - get rid of TEMPLOADs if possible and use vregs instead
13364  * - clean up usage of OP_P/OP_ opcodes
13365  * - cleanup usage of DUMMY_USE
13366  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13367  *   stack
13368  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13369  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13370  * - make sure handle_stack_args () is called before the branch is emitted
13371  * - when the new IR is done, get rid of all unused stuff
13372  * - COMPARE/BEQ as separate instructions or unify them ?
13373  *   - keeping them separate allows specialized compare instructions like
13374  *     compare_imm, compare_membase
13375  *   - most back ends unify fp compare+branch, fp compare+ceq
13376  * - integrate mono_save_args into inline_method
13377  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13378  * - handle long shift opts on 32 bit platforms somehow: they require 
13379  *   3 sregs (2 for arg1 and 1 for arg2)
13380  * - make byref a 'normal' type.
13381  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13382  *   variable if needed.
13383  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13384  *   like inline_method.
13385  * - remove inlining restrictions
13386  * - fix LNEG and enable cfold of INEG
13387  * - generalize x86 optimizations like ldelema as a peephole optimization
13388  * - add store_mem_imm for amd64
13389  * - optimize the loading of the interruption flag in the managed->native wrappers
13390  * - avoid special handling of OP_NOP in passes
13391  * - move code inserting instructions into one function/macro.
13392  * - try a coalescing phase after liveness analysis
13393  * - add float -> vreg conversion + local optimizations on !x86
13394  * - figure out how to handle decomposed branches during optimizations, ie.
13395  *   compare+branch, op_jump_table+op_br etc.
13396  * - promote RuntimeXHandles to vregs
13397  * - vtype cleanups:
13398  *   - add a NEW_VARLOADA_VREG macro
13399  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13400  *   accessing vtype fields.
13401  * - get rid of I8CONST on 64 bit platforms
13402  * - dealing with the increase in code size due to branches created during opcode
13403  *   decomposition:
13404  *   - use extended basic blocks
13405  *     - all parts of the JIT
13406  *     - handle_global_vregs () && local regalloc
13407  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13408  * - sources of increase in code size:
13409  *   - vtypes
13410  *   - long compares
13411  *   - isinst and castclass
13412  *   - lvregs not allocated to global registers even if used multiple times
13413  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13414  *   meaningful.
13415  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13416  * - add all micro optimizations from the old JIT
13417  * - put tree optimizations into the deadce pass
13418  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13419  *   specific function.
13420  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13421  *   fcompare + branchCC.
13422  * - create a helper function for allocating a stack slot, taking into account 
13423  *   MONO_CFG_HAS_SPILLUP.
13424  * - merge r68207.
13425  * - merge the ia64 switch changes.
13426  * - optimize mono_regstate2_alloc_int/float.
13427  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13428  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13429  *   parts of the tree could be separated by other instructions, killing the tree
13430  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13431  *   instructions if the result of the load is used multiple times ?
13432  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13433  * - LAST MERGE: 108395.
13434  * - when returning vtypes in registers, generate IR and append it to the end of the
13435  *   last bb instead of doing it in the epilog.
13436  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13437  */
13438
13439 /*
13440
13441 NOTES
13442 -----
13443
13444 - When to decompose opcodes:
13445   - earlier: this makes some optimizations hard to implement, since the low level IR
13446   no longer contains the neccessary information. But it is easier to do.
13447   - later: harder to implement, enables more optimizations.
13448 - Branches inside bblocks:
13449   - created when decomposing complex opcodes. 
13450     - branches to another bblock: harmless, but not tracked by the branch 
13451       optimizations, so need to branch to a label at the start of the bblock.
13452     - branches to inside the same bblock: very problematic, trips up the local
13453       reg allocator. Can be fixed by spitting the current bblock, but that is a
13454       complex operation, since some local vregs can become global vregs etc.
13455 - Local/global vregs:
13456   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13457     local register allocator.
13458   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13459     structure, created by mono_create_var (). Assigned to hregs or the stack by
13460     the global register allocator.
13461 - When to do optimizations like alu->alu_imm:
13462   - earlier -> saves work later on since the IR will be smaller/simpler
13463   - later -> can work on more instructions
13464 - Handling of valuetypes:
13465   - When a vtype is pushed on the stack, a new temporary is created, an 
13466     instruction computing its address (LDADDR) is emitted and pushed on
13467     the stack. Need to optimize cases when the vtype is used immediately as in
13468     argument passing, stloc etc.
13469 - Instead of the to_end stuff in the old JIT, simply call the function handling
13470   the values on the stack before emitting the last instruction of the bb.
13471 */
13472
13473 #endif /* DISABLE_JIT */