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