Get rid of the MONO_ARCH_ENABLE_LMF_IR define added by 0938c69a52654e02bbb8f0c2107183...
[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 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 handle_enum:
268         switch (type->type) {
269         case MONO_TYPE_I1:
270         case MONO_TYPE_U1:
271         case MONO_TYPE_BOOLEAN:
272                 return OP_MOVE;
273         case MONO_TYPE_I2:
274         case MONO_TYPE_U2:
275         case MONO_TYPE_CHAR:
276                 return OP_MOVE;
277         case MONO_TYPE_I4:
278         case MONO_TYPE_U4:
279                 return OP_MOVE;
280         case MONO_TYPE_I:
281         case MONO_TYPE_U:
282         case MONO_TYPE_PTR:
283         case MONO_TYPE_FNPTR:
284                 return OP_MOVE;
285         case MONO_TYPE_CLASS:
286         case MONO_TYPE_STRING:
287         case MONO_TYPE_OBJECT:
288         case MONO_TYPE_SZARRAY:
289         case MONO_TYPE_ARRAY:    
290                 return OP_MOVE;
291         case MONO_TYPE_I8:
292         case MONO_TYPE_U8:
293 #if SIZEOF_REGISTER == 8
294                 return OP_MOVE;
295 #else
296                 return OP_LMOVE;
297 #endif
298         case MONO_TYPE_R4:
299                 return OP_FMOVE;
300         case MONO_TYPE_R8:
301                 return OP_FMOVE;
302         case MONO_TYPE_VALUETYPE:
303                 if (type->data.klass->enumtype) {
304                         type = mono_class_enum_basetype (type->data.klass);
305                         goto handle_enum;
306                 }
307                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
308                         return OP_XMOVE;
309                 return OP_VMOVE;
310         case MONO_TYPE_TYPEDBYREF:
311                 return OP_VMOVE;
312         case MONO_TYPE_GENERICINST:
313                 type = &type->data.generic_class->container_class->byval_arg;
314                 goto handle_enum;
315         case MONO_TYPE_VAR:
316         case MONO_TYPE_MVAR:
317                 g_assert (cfg->generic_sharing_context);
318                 if (mini_type_var_is_vt (cfg, type))
319                         return OP_VMOVE;
320                 else
321                         return OP_MOVE;
322         default:
323                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
324         }
325         return -1;
326 }
327
328 void
329 mono_print_bb (MonoBasicBlock *bb, const char *msg)
330 {
331         int i;
332         MonoInst *tree;
333
334         printf ("\n%s %d: [IN: ", msg, bb->block_num);
335         for (i = 0; i < bb->in_count; ++i)
336                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
337         printf (", OUT: ");
338         for (i = 0; i < bb->out_count; ++i)
339                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
340         printf (" ]\n");
341         for (tree = bb->code; tree; tree = tree->next)
342                 mono_print_ins_index (-1, tree);
343 }
344
345 void
346 mono_create_helper_signatures (void)
347 {
348         helper_sig_domain_get = mono_create_icall_signature ("ptr");
349         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
350         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
351         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
352         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
353         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
354         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
355 }
356
357 /*
358  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
359  * foo<T> (int i) { ldarg.0; box T; }
360  */
361 #define UNVERIFIED do { \
362         if (cfg->gsharedvt) { \
363                 if (cfg->verbose_level > 2)                                                                     \
364                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
365                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
366                 goto exception_exit;                                                                                    \
367         }                                                                                                                                       \
368         if (mini_get_debug_options ()->break_on_unverified) \
369                 G_BREAKPOINT (); \
370         else \
371                 goto unverified; \
372 } while (0)
373
374 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
375
376 #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)
377
378 #define GET_BBLOCK(cfg,tblock,ip) do {  \
379                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
380                 if (!(tblock)) {        \
381                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
382             NEW_BBLOCK (cfg, (tblock)); \
383                         (tblock)->cil_code = (ip);      \
384                         ADD_BBLOCK (cfg, (tblock));     \
385                 } \
386         } while (0)
387
388 #if defined(TARGET_X86) || defined(TARGET_AMD64)
389 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
390                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
391                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
392                 (dest)->sreg1 = (sr1); \
393                 (dest)->sreg2 = (sr2); \
394                 (dest)->inst_imm = (imm); \
395                 (dest)->backend.shift_amount = (shift); \
396                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
397         } while (0)
398 #endif
399
400 #if SIZEOF_REGISTER == 8
401 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
402                 /* FIXME: Need to add many more cases */ \
403                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
404                         MonoInst *widen; \
405                         int dr = alloc_preg (cfg); \
406                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
407                         (ins)->sreg2 = widen->dreg; \
408                 } \
409         } while (0)
410 #else
411 #define ADD_WIDEN_OP(ins, arg1, arg2)
412 #endif
413
414 #define ADD_BINOP(op) do {      \
415                 MONO_INST_NEW (cfg, ins, (op)); \
416                 sp -= 2;        \
417                 ins->sreg1 = sp [0]->dreg;      \
418                 ins->sreg2 = sp [1]->dreg;      \
419                 type_from_op (ins, sp [0], sp [1]);     \
420                 CHECK_TYPE (ins);       \
421                 /* Have to insert a widening op */               \
422         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
423         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
424         MONO_ADD_INS ((cfg)->cbb, (ins)); \
425         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
426         } while (0)
427
428 #define ADD_UNOP(op) do {       \
429                 MONO_INST_NEW (cfg, ins, (op)); \
430                 sp--;   \
431                 ins->sreg1 = sp [0]->dreg;      \
432                 type_from_op (ins, sp [0], NULL);       \
433                 CHECK_TYPE (ins);       \
434         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
435         MONO_ADD_INS ((cfg)->cbb, (ins)); \
436                 *sp++ = mono_decompose_opcode (cfg, ins); \
437         } while (0)
438
439 #define ADD_BINCOND(next_block) do {    \
440                 MonoInst *cmp;  \
441                 sp -= 2; \
442                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
443                 cmp->sreg1 = sp [0]->dreg;      \
444                 cmp->sreg2 = sp [1]->dreg;      \
445                 type_from_op (cmp, sp [0], sp [1]);     \
446                 CHECK_TYPE (cmp);       \
447                 type_from_op (ins, sp [0], sp [1]);     \
448                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
449                 GET_BBLOCK (cfg, tblock, target);               \
450                 link_bblock (cfg, bblock, tblock);      \
451                 ins->inst_true_bb = tblock;     \
452                 if ((next_block)) {     \
453                         link_bblock (cfg, bblock, (next_block));        \
454                         ins->inst_false_bb = (next_block);      \
455                         start_new_bblock = 1;   \
456                 } else {        \
457                         GET_BBLOCK (cfg, tblock, ip);           \
458                         link_bblock (cfg, bblock, tblock);      \
459                         ins->inst_false_bb = tblock;    \
460                         start_new_bblock = 2;   \
461                 }       \
462                 if (sp != stack_start) {                                                                        \
463                     handle_stack_args (cfg, stack_start, sp - stack_start); \
464                         CHECK_UNVERIFIABLE (cfg); \
465                 } \
466         MONO_ADD_INS (bblock, cmp); \
467                 MONO_ADD_INS (bblock, ins);     \
468         } while (0)
469
470 /* *
471  * link_bblock: Links two basic blocks
472  *
473  * links two basic blocks in the control flow graph, the 'from'
474  * argument is the starting block and the 'to' argument is the block
475  * the control flow ends to after 'from'.
476  */
477 static void
478 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
479 {
480         MonoBasicBlock **newa;
481         int i, found;
482
483 #if 0
484         if (from->cil_code) {
485                 if (to->cil_code)
486                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
487                 else
488                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
489         } else {
490                 if (to->cil_code)
491                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
492                 else
493                         printf ("edge from entry to exit\n");
494         }
495 #endif
496
497         found = FALSE;
498         for (i = 0; i < from->out_count; ++i) {
499                 if (to == from->out_bb [i]) {
500                         found = TRUE;
501                         break;
502                 }
503         }
504         if (!found) {
505                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
506                 for (i = 0; i < from->out_count; ++i) {
507                         newa [i] = from->out_bb [i];
508                 }
509                 newa [i] = to;
510                 from->out_count++;
511                 from->out_bb = newa;
512         }
513
514         found = FALSE;
515         for (i = 0; i < to->in_count; ++i) {
516                 if (from == to->in_bb [i]) {
517                         found = TRUE;
518                         break;
519                 }
520         }
521         if (!found) {
522                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
523                 for (i = 0; i < to->in_count; ++i) {
524                         newa [i] = to->in_bb [i];
525                 }
526                 newa [i] = from;
527                 to->in_count++;
528                 to->in_bb = newa;
529         }
530 }
531
532 void
533 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
534 {
535         link_bblock (cfg, from, to);
536 }
537
538 /**
539  * mono_find_block_region:
540  *
541  *   We mark each basic block with a region ID. We use that to avoid BB
542  *   optimizations when blocks are in different regions.
543  *
544  * Returns:
545  *   A region token that encodes where this region is, and information
546  *   about the clause owner for this block.
547  *
548  *   The region encodes the try/catch/filter clause that owns this block
549  *   as well as the type.  -1 is a special value that represents a block
550  *   that is in none of try/catch/filter.
551  */
552 static int
553 mono_find_block_region (MonoCompile *cfg, int offset)
554 {
555         MonoMethodHeader *header = cfg->header;
556         MonoExceptionClause *clause;
557         int i;
558
559         for (i = 0; i < header->num_clauses; ++i) {
560                 clause = &header->clauses [i];
561                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
562                     (offset < (clause->handler_offset)))
563                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
564                            
565                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
566                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
567                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
568                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
569                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
570                         else
571                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
572                 }
573
574                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
575                         return ((i + 1) << 8) | clause->flags;
576         }
577
578         return -1;
579 }
580
581 static GList*
582 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
583 {
584         MonoMethodHeader *header = cfg->header;
585         MonoExceptionClause *clause;
586         int i;
587         GList *res = NULL;
588
589         for (i = 0; i < header->num_clauses; ++i) {
590                 clause = &header->clauses [i];
591                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
592                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
593                         if (clause->flags == type)
594                                 res = g_list_append (res, clause);
595                 }
596         }
597         return res;
598 }
599
600 static void
601 mono_create_spvar_for_region (MonoCompile *cfg, int region)
602 {
603         MonoInst *var;
604
605         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
606         if (var)
607                 return;
608
609         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
610         /* prevent it from being register allocated */
611         var->flags |= MONO_INST_INDIRECT;
612
613         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
614 }
615
616 MonoInst *
617 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
618 {
619         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
620 }
621
622 static MonoInst*
623 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
624 {
625         MonoInst *var;
626
627         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
628         if (var)
629                 return var;
630
631         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
632         /* prevent it from being register allocated */
633         var->flags |= MONO_INST_INDIRECT;
634
635         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
636
637         return var;
638 }
639
640 /*
641  * Returns the type used in the eval stack when @type is loaded.
642  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
643  */
644 void
645 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
646 {
647         MonoClass *klass;
648
649         inst->klass = klass = mono_class_from_mono_type (type);
650         if (type->byref) {
651                 inst->type = STACK_MP;
652                 return;
653         }
654
655 handle_enum:
656         switch (type->type) {
657         case MONO_TYPE_VOID:
658                 inst->type = STACK_INV;
659                 return;
660         case MONO_TYPE_I1:
661         case MONO_TYPE_U1:
662         case MONO_TYPE_BOOLEAN:
663         case MONO_TYPE_I2:
664         case MONO_TYPE_U2:
665         case MONO_TYPE_CHAR:
666         case MONO_TYPE_I4:
667         case MONO_TYPE_U4:
668                 inst->type = STACK_I4;
669                 return;
670         case MONO_TYPE_I:
671         case MONO_TYPE_U:
672         case MONO_TYPE_PTR:
673         case MONO_TYPE_FNPTR:
674                 inst->type = STACK_PTR;
675                 return;
676         case MONO_TYPE_CLASS:
677         case MONO_TYPE_STRING:
678         case MONO_TYPE_OBJECT:
679         case MONO_TYPE_SZARRAY:
680         case MONO_TYPE_ARRAY:    
681                 inst->type = STACK_OBJ;
682                 return;
683         case MONO_TYPE_I8:
684         case MONO_TYPE_U8:
685                 inst->type = STACK_I8;
686                 return;
687         case MONO_TYPE_R4:
688         case MONO_TYPE_R8:
689                 inst->type = STACK_R8;
690                 return;
691         case MONO_TYPE_VALUETYPE:
692                 if (type->data.klass->enumtype) {
693                         type = mono_class_enum_basetype (type->data.klass);
694                         goto handle_enum;
695                 } else {
696                         inst->klass = klass;
697                         inst->type = STACK_VTYPE;
698                         return;
699                 }
700         case MONO_TYPE_TYPEDBYREF:
701                 inst->klass = mono_defaults.typed_reference_class;
702                 inst->type = STACK_VTYPE;
703                 return;
704         case MONO_TYPE_GENERICINST:
705                 type = &type->data.generic_class->container_class->byval_arg;
706                 goto handle_enum;
707         case MONO_TYPE_VAR:
708         case MONO_TYPE_MVAR:
709                 g_assert (cfg->generic_sharing_context);
710                 if (mini_is_gsharedvt_type (cfg, type)) {
711                         g_assert (cfg->gsharedvt);
712                         inst->type = STACK_VTYPE;
713                 } else {
714                         inst->type = STACK_OBJ;
715                 }
716                 return;
717         default:
718                 g_error ("unknown type 0x%02x in eval stack type", type->type);
719         }
720 }
721
722 /*
723  * The following tables are used to quickly validate the IL code in type_from_op ().
724  */
725 static const char
726 bin_num_table [STACK_MAX] [STACK_MAX] = {
727         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
728         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
729         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
730         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
731         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
732         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
733         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
734         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
735 };
736
737 static const char 
738 neg_table [] = {
739         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
740 };
741
742 /* reduce the size of this table */
743 static const char
744 bin_int_table [STACK_MAX] [STACK_MAX] = {
745         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
746         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
747         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
748         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
749         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
750         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
754
755 static const char
756 bin_comp_table [STACK_MAX] [STACK_MAX] = {
757 /*      Inv i  L  p  F  &  O  vt */
758         {0},
759         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
760         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
761         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
762         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
763         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
764         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
765         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
766 };
767
768 /* reduce the size of this table */
769 static const char
770 shift_table [STACK_MAX] [STACK_MAX] = {
771         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
772         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
773         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
774         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
775         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
776         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, 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 };
780
781 /*
782  * Tables to map from the non-specific opcode to the matching
783  * type-specific opcode.
784  */
785 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
786 static const guint16
787 binops_op_map [STACK_MAX] = {
788         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
789 };
790
791 /* handles from CEE_NEG to CEE_CONV_U8 */
792 static const guint16
793 unops_op_map [STACK_MAX] = {
794         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
795 };
796
797 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
798 static const guint16
799 ovfops_op_map [STACK_MAX] = {
800         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
801 };
802
803 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
804 static const guint16
805 ovf2ops_op_map [STACK_MAX] = {
806         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
807 };
808
809 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
810 static const guint16
811 ovf3ops_op_map [STACK_MAX] = {
812         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
813 };
814
815 /* handles from CEE_BEQ to CEE_BLT_UN */
816 static const guint16
817 beqops_op_map [STACK_MAX] = {
818         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
819 };
820
821 /* handles from CEE_CEQ to CEE_CLT_UN */
822 static const guint16
823 ceqops_op_map [STACK_MAX] = {
824         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
825 };
826
827 /*
828  * Sets ins->type (the type on the eval stack) according to the
829  * type of the opcode and the arguments to it.
830  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
831  *
832  * FIXME: this function sets ins->type unconditionally in some cases, but
833  * it should set it to invalid for some types (a conv.x on an object)
834  */
835 static void
836 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
837
838         switch (ins->opcode) {
839         /* binops */
840         case CEE_ADD:
841         case CEE_SUB:
842         case CEE_MUL:
843         case CEE_DIV:
844         case CEE_REM:
845                 /* FIXME: check unverifiable args for STACK_MP */
846                 ins->type = bin_num_table [src1->type] [src2->type];
847                 ins->opcode += binops_op_map [ins->type];
848                 break;
849         case CEE_DIV_UN:
850         case CEE_REM_UN:
851         case CEE_AND:
852         case CEE_OR:
853         case CEE_XOR:
854                 ins->type = bin_int_table [src1->type] [src2->type];
855                 ins->opcode += binops_op_map [ins->type];
856                 break;
857         case CEE_SHL:
858         case CEE_SHR:
859         case CEE_SHR_UN:
860                 ins->type = shift_table [src1->type] [src2->type];
861                 ins->opcode += binops_op_map [ins->type];
862                 break;
863         case OP_COMPARE:
864         case OP_LCOMPARE:
865         case OP_ICOMPARE:
866                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
867                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
868                         ins->opcode = OP_LCOMPARE;
869                 else if (src1->type == STACK_R8)
870                         ins->opcode = OP_FCOMPARE;
871                 else
872                         ins->opcode = OP_ICOMPARE;
873                 break;
874         case OP_ICOMPARE_IMM:
875                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
876                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
877                         ins->opcode = OP_LCOMPARE_IMM;          
878                 break;
879         case CEE_BEQ:
880         case CEE_BGE:
881         case CEE_BGT:
882         case CEE_BLE:
883         case CEE_BLT:
884         case CEE_BNE_UN:
885         case CEE_BGE_UN:
886         case CEE_BGT_UN:
887         case CEE_BLE_UN:
888         case CEE_BLT_UN:
889                 ins->opcode += beqops_op_map [src1->type];
890                 break;
891         case OP_CEQ:
892                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
893                 ins->opcode += ceqops_op_map [src1->type];
894                 break;
895         case OP_CGT:
896         case OP_CGT_UN:
897         case OP_CLT:
898         case OP_CLT_UN:
899                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
900                 ins->opcode += ceqops_op_map [src1->type];
901                 break;
902         /* unops */
903         case CEE_NEG:
904                 ins->type = neg_table [src1->type];
905                 ins->opcode += unops_op_map [ins->type];
906                 break;
907         case CEE_NOT:
908                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
909                         ins->type = src1->type;
910                 else
911                         ins->type = STACK_INV;
912                 ins->opcode += unops_op_map [ins->type];
913                 break;
914         case CEE_CONV_I1:
915         case CEE_CONV_I2:
916         case CEE_CONV_I4:
917         case CEE_CONV_U4:
918                 ins->type = STACK_I4;
919                 ins->opcode += unops_op_map [src1->type];
920                 break;
921         case CEE_CONV_R_UN:
922                 ins->type = STACK_R8;
923                 switch (src1->type) {
924                 case STACK_I4:
925                 case STACK_PTR:
926                         ins->opcode = OP_ICONV_TO_R_UN;
927                         break;
928                 case STACK_I8:
929                         ins->opcode = OP_LCONV_TO_R_UN; 
930                         break;
931                 }
932                 break;
933         case CEE_CONV_OVF_I1:
934         case CEE_CONV_OVF_U1:
935         case CEE_CONV_OVF_I2:
936         case CEE_CONV_OVF_U2:
937         case CEE_CONV_OVF_I4:
938         case CEE_CONV_OVF_U4:
939                 ins->type = STACK_I4;
940                 ins->opcode += ovf3ops_op_map [src1->type];
941                 break;
942         case CEE_CONV_OVF_I_UN:
943         case CEE_CONV_OVF_U_UN:
944                 ins->type = STACK_PTR;
945                 ins->opcode += ovf2ops_op_map [src1->type];
946                 break;
947         case CEE_CONV_OVF_I1_UN:
948         case CEE_CONV_OVF_I2_UN:
949         case CEE_CONV_OVF_I4_UN:
950         case CEE_CONV_OVF_U1_UN:
951         case CEE_CONV_OVF_U2_UN:
952         case CEE_CONV_OVF_U4_UN:
953                 ins->type = STACK_I4;
954                 ins->opcode += ovf2ops_op_map [src1->type];
955                 break;
956         case CEE_CONV_U:
957                 ins->type = STACK_PTR;
958                 switch (src1->type) {
959                 case STACK_I4:
960                         ins->opcode = OP_ICONV_TO_U;
961                         break;
962                 case STACK_PTR:
963                 case STACK_MP:
964 #if SIZEOF_VOID_P == 8
965                         ins->opcode = OP_LCONV_TO_U;
966 #else
967                         ins->opcode = OP_MOVE;
968 #endif
969                         break;
970                 case STACK_I8:
971                         ins->opcode = OP_LCONV_TO_U;
972                         break;
973                 case STACK_R8:
974                         ins->opcode = OP_FCONV_TO_U;
975                         break;
976                 }
977                 break;
978         case CEE_CONV_I8:
979         case CEE_CONV_U8:
980                 ins->type = STACK_I8;
981                 ins->opcode += unops_op_map [src1->type];
982                 break;
983         case CEE_CONV_OVF_I8:
984         case CEE_CONV_OVF_U8:
985                 ins->type = STACK_I8;
986                 ins->opcode += ovf3ops_op_map [src1->type];
987                 break;
988         case CEE_CONV_OVF_U8_UN:
989         case CEE_CONV_OVF_I8_UN:
990                 ins->type = STACK_I8;
991                 ins->opcode += ovf2ops_op_map [src1->type];
992                 break;
993         case CEE_CONV_R4:
994         case CEE_CONV_R8:
995                 ins->type = STACK_R8;
996                 ins->opcode += unops_op_map [src1->type];
997                 break;
998         case OP_CKFINITE:
999                 ins->type = STACK_R8;           
1000                 break;
1001         case CEE_CONV_U2:
1002         case CEE_CONV_U1:
1003                 ins->type = STACK_I4;
1004                 ins->opcode += ovfops_op_map [src1->type];
1005                 break;
1006         case CEE_CONV_I:
1007         case CEE_CONV_OVF_I:
1008         case CEE_CONV_OVF_U:
1009                 ins->type = STACK_PTR;
1010                 ins->opcode += ovfops_op_map [src1->type];
1011                 break;
1012         case CEE_ADD_OVF:
1013         case CEE_ADD_OVF_UN:
1014         case CEE_MUL_OVF:
1015         case CEE_MUL_OVF_UN:
1016         case CEE_SUB_OVF:
1017         case CEE_SUB_OVF_UN:
1018                 ins->type = bin_num_table [src1->type] [src2->type];
1019                 ins->opcode += ovfops_op_map [src1->type];
1020                 if (ins->type == STACK_R8)
1021                         ins->type = STACK_INV;
1022                 break;
1023         case OP_LOAD_MEMBASE:
1024                 ins->type = STACK_PTR;
1025                 break;
1026         case OP_LOADI1_MEMBASE:
1027         case OP_LOADU1_MEMBASE:
1028         case OP_LOADI2_MEMBASE:
1029         case OP_LOADU2_MEMBASE:
1030         case OP_LOADI4_MEMBASE:
1031         case OP_LOADU4_MEMBASE:
1032                 ins->type = STACK_PTR;
1033                 break;
1034         case OP_LOADI8_MEMBASE:
1035                 ins->type = STACK_I8;
1036                 break;
1037         case OP_LOADR4_MEMBASE:
1038         case OP_LOADR8_MEMBASE:
1039                 ins->type = STACK_R8;
1040                 break;
1041         default:
1042                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1043                 break;
1044         }
1045
1046         if (ins->type == STACK_MP)
1047                 ins->klass = mono_defaults.object_class;
1048 }
1049
1050 static const char 
1051 ldind_type [] = {
1052         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1053 };
1054
1055 #if 0
1056
1057 static const char
1058 param_table [STACK_MAX] [STACK_MAX] = {
1059         {0},
1060 };
1061
1062 static int
1063 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1064         int i;
1065
1066         if (sig->hasthis) {
1067                 switch (args->type) {
1068                 case STACK_I4:
1069                 case STACK_I8:
1070                 case STACK_R8:
1071                 case STACK_VTYPE:
1072                 case STACK_INV:
1073                         return 0;
1074                 }
1075                 args++;
1076         }
1077         for (i = 0; i < sig->param_count; ++i) {
1078                 switch (args [i].type) {
1079                 case STACK_INV:
1080                         return 0;
1081                 case STACK_MP:
1082                         if (!sig->params [i]->byref)
1083                                 return 0;
1084                         continue;
1085                 case STACK_OBJ:
1086                         if (sig->params [i]->byref)
1087                                 return 0;
1088                         switch (sig->params [i]->type) {
1089                         case MONO_TYPE_CLASS:
1090                         case MONO_TYPE_STRING:
1091                         case MONO_TYPE_OBJECT:
1092                         case MONO_TYPE_SZARRAY:
1093                         case MONO_TYPE_ARRAY:
1094                                 break;
1095                         default:
1096                                 return 0;
1097                         }
1098                         continue;
1099                 case STACK_R8:
1100                         if (sig->params [i]->byref)
1101                                 return 0;
1102                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1103                                 return 0;
1104                         continue;
1105                 case STACK_PTR:
1106                 case STACK_I4:
1107                 case STACK_I8:
1108                 case STACK_VTYPE:
1109                         break;
1110                 }
1111                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1112                         return 0;*/
1113         }
1114         return 1;
1115 }
1116 #endif
1117
1118 /*
1119  * When we need a pointer to the current domain many times in a method, we
1120  * call mono_domain_get() once and we store the result in a local variable.
1121  * This function returns the variable that represents the MonoDomain*.
1122  */
1123 inline static MonoInst *
1124 mono_get_domainvar (MonoCompile *cfg)
1125 {
1126         if (!cfg->domainvar)
1127                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1128         return cfg->domainvar;
1129 }
1130
1131 /*
1132  * The got_var contains the address of the Global Offset Table when AOT 
1133  * compiling.
1134  */
1135 MonoInst *
1136 mono_get_got_var (MonoCompile *cfg)
1137 {
1138 #ifdef MONO_ARCH_NEED_GOT_VAR
1139         if (!cfg->compile_aot)
1140                 return NULL;
1141         if (!cfg->got_var) {
1142                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1143         }
1144         return cfg->got_var;
1145 #else
1146         return NULL;
1147 #endif
1148 }
1149
1150 static MonoInst *
1151 mono_get_vtable_var (MonoCompile *cfg)
1152 {
1153         g_assert (cfg->generic_sharing_context);
1154
1155         if (!cfg->rgctx_var) {
1156                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1157                 /* force the var to be stack allocated */
1158                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1159         }
1160
1161         return cfg->rgctx_var;
1162 }
1163
1164 static MonoType*
1165 type_from_stack_type (MonoInst *ins) {
1166         switch (ins->type) {
1167         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1168         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1169         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1170         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1171         case STACK_MP:
1172                 return &ins->klass->this_arg;
1173         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1174         case STACK_VTYPE: return &ins->klass->byval_arg;
1175         default:
1176                 g_error ("stack type %d to monotype not handled\n", ins->type);
1177         }
1178         return NULL;
1179 }
1180
1181 static G_GNUC_UNUSED int
1182 type_to_stack_type (MonoType *t)
1183 {
1184         t = mono_type_get_underlying_type (t);
1185         switch (t->type) {
1186         case MONO_TYPE_I1:
1187         case MONO_TYPE_U1:
1188         case MONO_TYPE_BOOLEAN:
1189         case MONO_TYPE_I2:
1190         case MONO_TYPE_U2:
1191         case MONO_TYPE_CHAR:
1192         case MONO_TYPE_I4:
1193         case MONO_TYPE_U4:
1194                 return STACK_I4;
1195         case MONO_TYPE_I:
1196         case MONO_TYPE_U:
1197         case MONO_TYPE_PTR:
1198         case MONO_TYPE_FNPTR:
1199                 return STACK_PTR;
1200         case MONO_TYPE_CLASS:
1201         case MONO_TYPE_STRING:
1202         case MONO_TYPE_OBJECT:
1203         case MONO_TYPE_SZARRAY:
1204         case MONO_TYPE_ARRAY:    
1205                 return STACK_OBJ;
1206         case MONO_TYPE_I8:
1207         case MONO_TYPE_U8:
1208                 return STACK_I8;
1209         case MONO_TYPE_R4:
1210         case MONO_TYPE_R8:
1211                 return STACK_R8;
1212         case MONO_TYPE_VALUETYPE:
1213         case MONO_TYPE_TYPEDBYREF:
1214                 return STACK_VTYPE;
1215         case MONO_TYPE_GENERICINST:
1216                 if (mono_type_generic_inst_is_valuetype (t))
1217                         return STACK_VTYPE;
1218                 else
1219                         return STACK_OBJ;
1220                 break;
1221         default:
1222                 g_assert_not_reached ();
1223         }
1224
1225         return -1;
1226 }
1227
1228 static MonoClass*
1229 array_access_to_klass (int opcode)
1230 {
1231         switch (opcode) {
1232         case CEE_LDELEM_U1:
1233                 return mono_defaults.byte_class;
1234         case CEE_LDELEM_U2:
1235                 return mono_defaults.uint16_class;
1236         case CEE_LDELEM_I:
1237         case CEE_STELEM_I:
1238                 return mono_defaults.int_class;
1239         case CEE_LDELEM_I1:
1240         case CEE_STELEM_I1:
1241                 return mono_defaults.sbyte_class;
1242         case CEE_LDELEM_I2:
1243         case CEE_STELEM_I2:
1244                 return mono_defaults.int16_class;
1245         case CEE_LDELEM_I4:
1246         case CEE_STELEM_I4:
1247                 return mono_defaults.int32_class;
1248         case CEE_LDELEM_U4:
1249                 return mono_defaults.uint32_class;
1250         case CEE_LDELEM_I8:
1251         case CEE_STELEM_I8:
1252                 return mono_defaults.int64_class;
1253         case CEE_LDELEM_R4:
1254         case CEE_STELEM_R4:
1255                 return mono_defaults.single_class;
1256         case CEE_LDELEM_R8:
1257         case CEE_STELEM_R8:
1258                 return mono_defaults.double_class;
1259         case CEE_LDELEM_REF:
1260         case CEE_STELEM_REF:
1261                 return mono_defaults.object_class;
1262         default:
1263                 g_assert_not_reached ();
1264         }
1265         return NULL;
1266 }
1267
1268 /*
1269  * We try to share variables when possible
1270  */
1271 static MonoInst *
1272 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1273 {
1274         MonoInst *res;
1275         int pos, vnum;
1276
1277         /* inlining can result in deeper stacks */ 
1278         if (slot >= cfg->header->max_stack)
1279                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1280
1281         pos = ins->type - 1 + slot * STACK_MAX;
1282
1283         switch (ins->type) {
1284         case STACK_I4:
1285         case STACK_I8:
1286         case STACK_R8:
1287         case STACK_PTR:
1288         case STACK_MP:
1289         case STACK_OBJ:
1290                 if ((vnum = cfg->intvars [pos]))
1291                         return cfg->varinfo [vnum];
1292                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1293                 cfg->intvars [pos] = res->inst_c0;
1294                 break;
1295         default:
1296                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1297         }
1298         return res;
1299 }
1300
1301 static void
1302 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1303 {
1304         /* 
1305          * Don't use this if a generic_context is set, since that means AOT can't
1306          * look up the method using just the image+token.
1307          * table == 0 means this is a reference made from a wrapper.
1308          */
1309         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1310                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1311                 jump_info_token->image = image;
1312                 jump_info_token->token = token;
1313                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1314         }
1315 }
1316
1317 /*
1318  * This function is called to handle items that are left on the evaluation stack
1319  * at basic block boundaries. What happens is that we save the values to local variables
1320  * and we reload them later when first entering the target basic block (with the
1321  * handle_loaded_temps () function).
1322  * A single joint point will use the same variables (stored in the array bb->out_stack or
1323  * bb->in_stack, if the basic block is before or after the joint point).
1324  *
1325  * This function needs to be called _before_ emitting the last instruction of
1326  * the bb (i.e. before emitting a branch).
1327  * If the stack merge fails at a join point, cfg->unverifiable is set.
1328  */
1329 static void
1330 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1331 {
1332         int i, bindex;
1333         MonoBasicBlock *bb = cfg->cbb;
1334         MonoBasicBlock *outb;
1335         MonoInst *inst, **locals;
1336         gboolean found;
1337
1338         if (!count)
1339                 return;
1340         if (cfg->verbose_level > 3)
1341                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1342         if (!bb->out_scount) {
1343                 bb->out_scount = count;
1344                 //printf ("bblock %d has out:", bb->block_num);
1345                 found = FALSE;
1346                 for (i = 0; i < bb->out_count; ++i) {
1347                         outb = bb->out_bb [i];
1348                         /* exception handlers are linked, but they should not be considered for stack args */
1349                         if (outb->flags & BB_EXCEPTION_HANDLER)
1350                                 continue;
1351                         //printf (" %d", outb->block_num);
1352                         if (outb->in_stack) {
1353                                 found = TRUE;
1354                                 bb->out_stack = outb->in_stack;
1355                                 break;
1356                         }
1357                 }
1358                 //printf ("\n");
1359                 if (!found) {
1360                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1361                         for (i = 0; i < count; ++i) {
1362                                 /* 
1363                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1364                                  * stack slot and if they are of the same type.
1365                                  * This won't cause conflicts since if 'local' is used to 
1366                                  * store one of the values in the in_stack of a bblock, then
1367                                  * the same variable will be used for the same outgoing stack 
1368                                  * slot as well. 
1369                                  * This doesn't work when inlining methods, since the bblocks
1370                                  * in the inlined methods do not inherit their in_stack from
1371                                  * the bblock they are inlined to. See bug #58863 for an
1372                                  * example.
1373                                  */
1374                                 if (cfg->inlined_method)
1375                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1376                                 else
1377                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1378                         }
1379                 }
1380         }
1381
1382         for (i = 0; i < bb->out_count; ++i) {
1383                 outb = bb->out_bb [i];
1384                 /* exception handlers are linked, but they should not be considered for stack args */
1385                 if (outb->flags & BB_EXCEPTION_HANDLER)
1386                         continue;
1387                 if (outb->in_scount) {
1388                         if (outb->in_scount != bb->out_scount) {
1389                                 cfg->unverifiable = TRUE;
1390                                 return;
1391                         }
1392                         continue; /* check they are the same locals */
1393                 }
1394                 outb->in_scount = count;
1395                 outb->in_stack = bb->out_stack;
1396         }
1397
1398         locals = bb->out_stack;
1399         cfg->cbb = bb;
1400         for (i = 0; i < count; ++i) {
1401                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1402                 inst->cil_code = sp [i]->cil_code;
1403                 sp [i] = locals [i];
1404                 if (cfg->verbose_level > 3)
1405                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1406         }
1407
1408         /*
1409          * It is possible that the out bblocks already have in_stack assigned, and
1410          * the in_stacks differ. In this case, we will store to all the different 
1411          * in_stacks.
1412          */
1413
1414         found = TRUE;
1415         bindex = 0;
1416         while (found) {
1417                 /* Find a bblock which has a different in_stack */
1418                 found = FALSE;
1419                 while (bindex < bb->out_count) {
1420                         outb = bb->out_bb [bindex];
1421                         /* exception handlers are linked, but they should not be considered for stack args */
1422                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1423                                 bindex++;
1424                                 continue;
1425                         }
1426                         if (outb->in_stack != locals) {
1427                                 for (i = 0; i < count; ++i) {
1428                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1429                                         inst->cil_code = sp [i]->cil_code;
1430                                         sp [i] = locals [i];
1431                                         if (cfg->verbose_level > 3)
1432                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1433                                 }
1434                                 locals = outb->in_stack;
1435                                 found = TRUE;
1436                                 break;
1437                         }
1438                         bindex ++;
1439                 }
1440         }
1441 }
1442
1443 /* Emit code which loads interface_offsets [klass->interface_id]
1444  * The array is stored in memory before vtable.
1445 */
1446 static void
1447 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1448 {
1449         if (cfg->compile_aot) {
1450                 int ioffset_reg = alloc_preg (cfg);
1451                 int iid_reg = alloc_preg (cfg);
1452
1453                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1454                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1455                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1456         }
1457         else {
1458                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1459         }
1460 }
1461
1462 static void
1463 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1464 {
1465         int ibitmap_reg = alloc_preg (cfg);
1466 #ifdef COMPRESSED_INTERFACE_BITMAP
1467         MonoInst *args [2];
1468         MonoInst *res, *ins;
1469         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1470         MONO_ADD_INS (cfg->cbb, ins);
1471         args [0] = ins;
1472         if (cfg->compile_aot)
1473                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1474         else
1475                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1476         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1477         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1478 #else
1479         int ibitmap_byte_reg = alloc_preg (cfg);
1480
1481         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1482
1483         if (cfg->compile_aot) {
1484                 int iid_reg = alloc_preg (cfg);
1485                 int shifted_iid_reg = alloc_preg (cfg);
1486                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1487                 int masked_iid_reg = alloc_preg (cfg);
1488                 int iid_one_bit_reg = alloc_preg (cfg);
1489                 int iid_bit_reg = alloc_preg (cfg);
1490                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1491                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1492                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1493                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1494                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1495                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1496                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1497                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1498         } else {
1499                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1500                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1501         }
1502 #endif
1503 }
1504
1505 /* 
1506  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1507  * stored in "klass_reg" implements the interface "klass".
1508  */
1509 static void
1510 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1511 {
1512         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1513 }
1514
1515 /* 
1516  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1517  * stored in "vtable_reg" implements the interface "klass".
1518  */
1519 static void
1520 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1521 {
1522         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1523 }
1524
1525 /* 
1526  * Emit code which checks whenever the interface id of @klass is smaller than
1527  * than the value given by max_iid_reg.
1528 */
1529 static void
1530 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1531                                                  MonoBasicBlock *false_target)
1532 {
1533         if (cfg->compile_aot) {
1534                 int iid_reg = alloc_preg (cfg);
1535                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1536                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1537         }
1538         else
1539                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1540         if (false_target)
1541                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1542         else
1543                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1544 }
1545
1546 /* Same as above, but obtains max_iid from a vtable */
1547 static void
1548 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1549                                                                  MonoBasicBlock *false_target)
1550 {
1551         int max_iid_reg = alloc_preg (cfg);
1552                 
1553         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1554         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1555 }
1556
1557 /* Same as above, but obtains max_iid from a klass */
1558 static void
1559 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1560                                                                  MonoBasicBlock *false_target)
1561 {
1562         int max_iid_reg = alloc_preg (cfg);
1563
1564         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1565         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1566 }
1567
1568 static void
1569 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1570 {
1571         int idepth_reg = alloc_preg (cfg);
1572         int stypes_reg = alloc_preg (cfg);
1573         int stype = alloc_preg (cfg);
1574
1575         mono_class_setup_supertypes (klass);
1576
1577         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1578                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1580                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1581         }
1582         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1583         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1584         if (klass_ins) {
1585                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1586         } else if (cfg->compile_aot) {
1587                 int const_reg = alloc_preg (cfg);
1588                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1589                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1590         } else {
1591                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1592         }
1593         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1594 }
1595
1596 static void
1597 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1598 {
1599         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1600 }
1601
1602 static void
1603 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1604 {
1605         int intf_reg = alloc_preg (cfg);
1606
1607         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1608         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1609         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1610         if (true_target)
1611                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1612         else
1613                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1614 }
1615
1616 /*
1617  * Variant of the above that takes a register to the class, not the vtable.
1618  */
1619 static void
1620 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1621 {
1622         int intf_bit_reg = alloc_preg (cfg);
1623
1624         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1625         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1626         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1627         if (true_target)
1628                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1629         else
1630                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1631 }
1632
1633 static inline void
1634 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1635 {
1636         if (klass_inst) {
1637                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1638         } else if (cfg->compile_aot) {
1639                 int const_reg = alloc_preg (cfg);
1640                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1641                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1642         } else {
1643                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1644         }
1645         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1646 }
1647
1648 static inline void
1649 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1650 {
1651         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1652 }
1653
1654 static inline void
1655 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1656 {
1657         if (cfg->compile_aot) {
1658                 int const_reg = alloc_preg (cfg);
1659                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1660                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1661         } else {
1662                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1663         }
1664         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1665 }
1666
1667 static void
1668 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1669         
1670 static void
1671 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1672 {
1673         if (klass->rank) {
1674                 int rank_reg = alloc_preg (cfg);
1675                 int eclass_reg = alloc_preg (cfg);
1676
1677                 g_assert (!klass_inst);
1678                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1679                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1680                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1681                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1682                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1683                 if (klass->cast_class == mono_defaults.object_class) {
1684                         int parent_reg = alloc_preg (cfg);
1685                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1686                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1687                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1688                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1689                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1690                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1691                 } else if (klass->cast_class == mono_defaults.enum_class) {
1692                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1693                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1694                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1695                 } else {
1696                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1697                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1698                 }
1699
1700                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1701                         /* Check that the object is a vector too */
1702                         int bounds_reg = alloc_preg (cfg);
1703                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1704                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1705                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1706                 }
1707         } else {
1708                 int idepth_reg = alloc_preg (cfg);
1709                 int stypes_reg = alloc_preg (cfg);
1710                 int stype = alloc_preg (cfg);
1711
1712                 mono_class_setup_supertypes (klass);
1713
1714                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1715                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1716                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1717                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1718                 }
1719                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1720                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1721                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1722         }
1723 }
1724
1725 static void
1726 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1727 {
1728         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1729 }
1730
1731 static void 
1732 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1733 {
1734         int val_reg;
1735
1736         g_assert (val == 0);
1737
1738         if (align == 0)
1739                 align = 4;
1740
1741         if ((size <= 4) && (size <= align)) {
1742                 switch (size) {
1743                 case 1:
1744                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1745                         return;
1746                 case 2:
1747                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1748                         return;
1749                 case 4:
1750                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1751                         return;
1752 #if SIZEOF_REGISTER == 8
1753                 case 8:
1754                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1755                         return;
1756 #endif
1757                 }
1758         }
1759
1760         val_reg = alloc_preg (cfg);
1761
1762         if (SIZEOF_REGISTER == 8)
1763                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1764         else
1765                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1766
1767         if (align < 4) {
1768                 /* This could be optimized further if neccesary */
1769                 while (size >= 1) {
1770                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1771                         offset += 1;
1772                         size -= 1;
1773                 }
1774                 return;
1775         }       
1776
1777 #if !NO_UNALIGNED_ACCESS
1778         if (SIZEOF_REGISTER == 8) {
1779                 if (offset % 8) {
1780                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1781                         offset += 4;
1782                         size -= 4;
1783                 }
1784                 while (size >= 8) {
1785                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1786                         offset += 8;
1787                         size -= 8;
1788                 }
1789         }       
1790 #endif
1791
1792         while (size >= 4) {
1793                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1794                 offset += 4;
1795                 size -= 4;
1796         }
1797         while (size >= 2) {
1798                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1799                 offset += 2;
1800                 size -= 2;
1801         }
1802         while (size >= 1) {
1803                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1804                 offset += 1;
1805                 size -= 1;
1806         }
1807 }
1808
1809 void 
1810 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1811 {
1812         int cur_reg;
1813
1814         if (align == 0)
1815                 align = 4;
1816
1817         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1818         g_assert (size < 10000);
1819
1820         if (align < 4) {
1821                 /* This could be optimized further if neccesary */
1822                 while (size >= 1) {
1823                         cur_reg = alloc_preg (cfg);
1824                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1825                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1826                         doffset += 1;
1827                         soffset += 1;
1828                         size -= 1;
1829                 }
1830         }
1831
1832 #if !NO_UNALIGNED_ACCESS
1833         if (SIZEOF_REGISTER == 8) {
1834                 while (size >= 8) {
1835                         cur_reg = alloc_preg (cfg);
1836                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1837                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1838                         doffset += 8;
1839                         soffset += 8;
1840                         size -= 8;
1841                 }
1842         }       
1843 #endif
1844
1845         while (size >= 4) {
1846                 cur_reg = alloc_preg (cfg);
1847                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1848                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1849                 doffset += 4;
1850                 soffset += 4;
1851                 size -= 4;
1852         }
1853         while (size >= 2) {
1854                 cur_reg = alloc_preg (cfg);
1855                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1857                 doffset += 2;
1858                 soffset += 2;
1859                 size -= 2;
1860         }
1861         while (size >= 1) {
1862                 cur_reg = alloc_preg (cfg);
1863                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1864                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1865                 doffset += 1;
1866                 soffset += 1;
1867                 size -= 1;
1868         }
1869 }
1870
1871 /*
1872  * emit_push_lmf:
1873  *
1874  *   Emit IR to push the current LMF onto the LMF stack.
1875  */
1876 static void
1877 emit_push_lmf (MonoCompile *cfg)
1878 {
1879         /*
1880          * Emit IR to push the LMF:
1881          * lmf_addr = <lmf_addr from tls>
1882          * lmf->lmf_addr = lmf_addr
1883          * lmf->prev_lmf = *lmf_addr
1884          * *lmf_addr = lmf
1885          */
1886         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1887         MonoInst *ins, *lmf_ins;
1888
1889         if (!cfg->lmf_ir)
1890                 return;
1891
1892         lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
1893         if (lmf_ins)
1894                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1895         else
1896                 lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1897         lmf_addr_reg = lmf_ins->dreg;
1898
1899         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1900         lmf_reg = ins->dreg;
1901         /* Save lmf_addr */
1902         if (!cfg->lmf_addr_var)
1903                 cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1904         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, cfg->lmf_addr_var->dreg, lmf_ins->dreg);
1905         prev_lmf_reg = alloc_preg (cfg);
1906         /* Save previous_lmf */
1907         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_addr_reg, 0);
1908         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
1909         /* Set new lmf */
1910         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, lmf_reg);
1911 }
1912
1913 /*
1914  * emit_push_lmf:
1915  *
1916  *   Emit IR to pop the current LMF from the LMF stack.
1917  */
1918 static void
1919 emit_pop_lmf (MonoCompile *cfg)
1920 {
1921         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
1922         MonoInst *ins;
1923
1924         if (!cfg->lmf_ir)
1925                 return;
1926
1927         /*
1928          * Emit IR to pop the LMF:
1929          * *(lmf->lmf_addr) = lmf->prev_lmf
1930          */
1931         cfg->cbb = cfg->bb_exit;
1932         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1933         lmf_reg = ins->dreg;
1934         /* This could be called before emit_push_lmf () */
1935         if (!cfg->lmf_addr_var)
1936                 cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1937         lmf_addr_reg = cfg->lmf_addr_var->dreg;
1938         prev_lmf_reg = alloc_preg (cfg);
1939         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
1940         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
1941 }
1942
1943 static int
1944 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1945 {
1946         if (type->byref)
1947                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1948
1949 handle_enum:
1950         type = mini_get_basic_type_from_generic (gsctx, type);
1951         switch (type->type) {
1952         case MONO_TYPE_VOID:
1953                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1954         case MONO_TYPE_I1:
1955         case MONO_TYPE_U1:
1956         case MONO_TYPE_BOOLEAN:
1957         case MONO_TYPE_I2:
1958         case MONO_TYPE_U2:
1959         case MONO_TYPE_CHAR:
1960         case MONO_TYPE_I4:
1961         case MONO_TYPE_U4:
1962                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1963         case MONO_TYPE_I:
1964         case MONO_TYPE_U:
1965         case MONO_TYPE_PTR:
1966         case MONO_TYPE_FNPTR:
1967                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1968         case MONO_TYPE_CLASS:
1969         case MONO_TYPE_STRING:
1970         case MONO_TYPE_OBJECT:
1971         case MONO_TYPE_SZARRAY:
1972         case MONO_TYPE_ARRAY:    
1973                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1974         case MONO_TYPE_I8:
1975         case MONO_TYPE_U8:
1976                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1977         case MONO_TYPE_R4:
1978         case MONO_TYPE_R8:
1979                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1980         case MONO_TYPE_VALUETYPE:
1981                 if (type->data.klass->enumtype) {
1982                         type = mono_class_enum_basetype (type->data.klass);
1983                         goto handle_enum;
1984                 } else
1985                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1986         case MONO_TYPE_TYPEDBYREF:
1987                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1988         case MONO_TYPE_GENERICINST:
1989                 type = &type->data.generic_class->container_class->byval_arg;
1990                 goto handle_enum;
1991         case MONO_TYPE_VAR:
1992         case MONO_TYPE_MVAR:
1993                 /* gsharedvt */
1994                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1995         default:
1996                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1997         }
1998         return -1;
1999 }
2000
2001 /*
2002  * target_type_is_incompatible:
2003  * @cfg: MonoCompile context
2004  *
2005  * Check that the item @arg on the evaluation stack can be stored
2006  * in the target type (can be a local, or field, etc).
2007  * The cfg arg can be used to check if we need verification or just
2008  * validity checks.
2009  *
2010  * Returns: non-0 value if arg can't be stored on a target.
2011  */
2012 static int
2013 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2014 {
2015         MonoType *simple_type;
2016         MonoClass *klass;
2017
2018         if (target->byref) {
2019                 /* FIXME: check that the pointed to types match */
2020                 if (arg->type == STACK_MP)
2021                         return arg->klass != mono_class_from_mono_type (target);
2022                 if (arg->type == STACK_PTR)
2023                         return 0;
2024                 return 1;
2025         }
2026
2027         simple_type = mono_type_get_underlying_type (target);
2028         switch (simple_type->type) {
2029         case MONO_TYPE_VOID:
2030                 return 1;
2031         case MONO_TYPE_I1:
2032         case MONO_TYPE_U1:
2033         case MONO_TYPE_BOOLEAN:
2034         case MONO_TYPE_I2:
2035         case MONO_TYPE_U2:
2036         case MONO_TYPE_CHAR:
2037         case MONO_TYPE_I4:
2038         case MONO_TYPE_U4:
2039                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2040                         return 1;
2041                 return 0;
2042         case MONO_TYPE_PTR:
2043                 /* STACK_MP is needed when setting pinned locals */
2044                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2045                         return 1;
2046                 return 0;
2047         case MONO_TYPE_I:
2048         case MONO_TYPE_U:
2049         case MONO_TYPE_FNPTR:
2050                 /* 
2051                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2052                  * in native int. (#688008).
2053                  */
2054                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2055                         return 1;
2056                 return 0;
2057         case MONO_TYPE_CLASS:
2058         case MONO_TYPE_STRING:
2059         case MONO_TYPE_OBJECT:
2060         case MONO_TYPE_SZARRAY:
2061         case MONO_TYPE_ARRAY:    
2062                 if (arg->type != STACK_OBJ)
2063                         return 1;
2064                 /* FIXME: check type compatibility */
2065                 return 0;
2066         case MONO_TYPE_I8:
2067         case MONO_TYPE_U8:
2068                 if (arg->type != STACK_I8)
2069                         return 1;
2070                 return 0;
2071         case MONO_TYPE_R4:
2072         case MONO_TYPE_R8:
2073                 if (arg->type != STACK_R8)
2074                         return 1;
2075                 return 0;
2076         case MONO_TYPE_VALUETYPE:
2077                 if (arg->type != STACK_VTYPE)
2078                         return 1;
2079                 klass = mono_class_from_mono_type (simple_type);
2080                 if (klass != arg->klass)
2081                         return 1;
2082                 return 0;
2083         case MONO_TYPE_TYPEDBYREF:
2084                 if (arg->type != STACK_VTYPE)
2085                         return 1;
2086                 klass = mono_class_from_mono_type (simple_type);
2087                 if (klass != arg->klass)
2088                         return 1;
2089                 return 0;
2090         case MONO_TYPE_GENERICINST:
2091                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2092                         if (arg->type != STACK_VTYPE)
2093                                 return 1;
2094                         klass = mono_class_from_mono_type (simple_type);
2095                         if (klass != arg->klass)
2096                                 return 1;
2097                         return 0;
2098                 } else {
2099                         if (arg->type != STACK_OBJ)
2100                                 return 1;
2101                         /* FIXME: check type compatibility */
2102                         return 0;
2103                 }
2104         case MONO_TYPE_VAR:
2105         case MONO_TYPE_MVAR:
2106                 g_assert (cfg->generic_sharing_context);
2107                 if (mini_type_var_is_vt (cfg, simple_type)) {
2108                         if (arg->type != STACK_VTYPE)
2109                                 return 1;
2110                 } else {
2111                         if (arg->type != STACK_OBJ)
2112                                 return 1;
2113                 }
2114                 return 0;
2115         default:
2116                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2117         }
2118         return 1;
2119 }
2120
2121 /*
2122  * Prepare arguments for passing to a function call.
2123  * Return a non-zero value if the arguments can't be passed to the given
2124  * signature.
2125  * The type checks are not yet complete and some conversions may need
2126  * casts on 32 or 64 bit architectures.
2127  *
2128  * FIXME: implement this using target_type_is_incompatible ()
2129  */
2130 static int
2131 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2132 {
2133         MonoType *simple_type;
2134         int i;
2135
2136         if (sig->hasthis) {
2137                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2138                         return 1;
2139                 args++;
2140         }
2141         for (i = 0; i < sig->param_count; ++i) {
2142                 if (sig->params [i]->byref) {
2143                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2144                                 return 1;
2145                         continue;
2146                 }
2147                 simple_type = sig->params [i];
2148                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2149 handle_enum:
2150                 switch (simple_type->type) {
2151                 case MONO_TYPE_VOID:
2152                         return 1;
2153                         continue;
2154                 case MONO_TYPE_I1:
2155                 case MONO_TYPE_U1:
2156                 case MONO_TYPE_BOOLEAN:
2157                 case MONO_TYPE_I2:
2158                 case MONO_TYPE_U2:
2159                 case MONO_TYPE_CHAR:
2160                 case MONO_TYPE_I4:
2161                 case MONO_TYPE_U4:
2162                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2163                                 return 1;
2164                         continue;
2165                 case MONO_TYPE_I:
2166                 case MONO_TYPE_U:
2167                 case MONO_TYPE_PTR:
2168                 case MONO_TYPE_FNPTR:
2169                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2170                                 return 1;
2171                         continue;
2172                 case MONO_TYPE_CLASS:
2173                 case MONO_TYPE_STRING:
2174                 case MONO_TYPE_OBJECT:
2175                 case MONO_TYPE_SZARRAY:
2176                 case MONO_TYPE_ARRAY:    
2177                         if (args [i]->type != STACK_OBJ)
2178                                 return 1;
2179                         continue;
2180                 case MONO_TYPE_I8:
2181                 case MONO_TYPE_U8:
2182                         if (args [i]->type != STACK_I8)
2183                                 return 1;
2184                         continue;
2185                 case MONO_TYPE_R4:
2186                 case MONO_TYPE_R8:
2187                         if (args [i]->type != STACK_R8)
2188                                 return 1;
2189                         continue;
2190                 case MONO_TYPE_VALUETYPE:
2191                         if (simple_type->data.klass->enumtype) {
2192                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2193                                 goto handle_enum;
2194                         }
2195                         if (args [i]->type != STACK_VTYPE)
2196                                 return 1;
2197                         continue;
2198                 case MONO_TYPE_TYPEDBYREF:
2199                         if (args [i]->type != STACK_VTYPE)
2200                                 return 1;
2201                         continue;
2202                 case MONO_TYPE_GENERICINST:
2203                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2204                         goto handle_enum;
2205                 case MONO_TYPE_VAR:
2206                 case MONO_TYPE_MVAR:
2207                         /* gsharedvt */
2208                         if (args [i]->type != STACK_VTYPE)
2209                                 return 1;
2210                         continue;
2211                 default:
2212                         g_error ("unknown type 0x%02x in check_call_signature",
2213                                  simple_type->type);
2214                 }
2215         }
2216         return 0;
2217 }
2218
2219 static int
2220 callvirt_to_call (int opcode)
2221 {
2222         switch (opcode) {
2223         case OP_CALLVIRT:
2224                 return OP_CALL;
2225         case OP_VOIDCALLVIRT:
2226                 return OP_VOIDCALL;
2227         case OP_FCALLVIRT:
2228                 return OP_FCALL;
2229         case OP_VCALLVIRT:
2230                 return OP_VCALL;
2231         case OP_LCALLVIRT:
2232                 return OP_LCALL;
2233         default:
2234                 g_assert_not_reached ();
2235         }
2236
2237         return -1;
2238 }
2239
2240 static int
2241 callvirt_to_call_membase (int opcode)
2242 {
2243         switch (opcode) {
2244         case OP_CALLVIRT:
2245                 return OP_CALL_MEMBASE;
2246         case OP_VOIDCALLVIRT:
2247                 return OP_VOIDCALL_MEMBASE;
2248         case OP_FCALLVIRT:
2249                 return OP_FCALL_MEMBASE;
2250         case OP_LCALLVIRT:
2251                 return OP_LCALL_MEMBASE;
2252         case OP_VCALLVIRT:
2253                 return OP_VCALL_MEMBASE;
2254         default:
2255                 g_assert_not_reached ();
2256         }
2257
2258         return -1;
2259 }
2260
2261 #ifdef MONO_ARCH_HAVE_IMT
2262 /* Either METHOD or IMT_ARG needs to be set */
2263 static void
2264 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2265 {
2266         int method_reg;
2267
2268         if (COMPILE_LLVM (cfg)) {
2269                 method_reg = alloc_preg (cfg);
2270
2271                 if (imt_arg) {
2272                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2273                 } else if (cfg->compile_aot) {
2274                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2275                 } else {
2276                         MonoInst *ins;
2277                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2278                         ins->inst_p0 = method;
2279                         ins->dreg = method_reg;
2280                         MONO_ADD_INS (cfg->cbb, ins);
2281                 }
2282
2283 #ifdef ENABLE_LLVM
2284                 call->imt_arg_reg = method_reg;
2285 #endif
2286 #ifdef MONO_ARCH_IMT_REG
2287         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2288 #else
2289         /* Need this to keep the IMT arg alive */
2290         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2291 #endif
2292                 return;
2293         }
2294
2295 #ifdef MONO_ARCH_IMT_REG
2296         method_reg = alloc_preg (cfg);
2297
2298         if (imt_arg) {
2299                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2300         } else if (cfg->compile_aot) {
2301                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2302         } else {
2303                 MonoInst *ins;
2304                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2305                 ins->inst_p0 = method;
2306                 ins->dreg = method_reg;
2307                 MONO_ADD_INS (cfg->cbb, ins);
2308         }
2309
2310         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2311 #else
2312         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2313 #endif
2314 }
2315 #endif
2316
2317 static MonoJumpInfo *
2318 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2319 {
2320         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2321
2322         ji->ip.i = ip;
2323         ji->type = type;
2324         ji->data.target = target;
2325
2326         return ji;
2327 }
2328
2329 static int
2330 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2331 {
2332         if (cfg->generic_sharing_context)
2333                 return mono_class_check_context_used (klass);
2334         else
2335                 return 0;
2336 }
2337
2338 static int
2339 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2340 {
2341         if (cfg->generic_sharing_context)
2342                 return mono_method_check_context_used (method);
2343         else
2344                 return 0;
2345 }
2346
2347 /*
2348  * check_method_sharing:
2349  *
2350  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2351  */
2352 static void
2353 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2354 {
2355         gboolean pass_vtable = FALSE;
2356         gboolean pass_mrgctx = FALSE;
2357
2358         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2359                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2360                 gboolean sharable = FALSE;
2361
2362                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2363                         sharable = TRUE;
2364                 } else {
2365                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2366                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2367                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2368
2369                         sharable = sharing_enabled && context_sharable;
2370                 }
2371
2372                 /*
2373                  * Pass vtable iff target method might
2374                  * be shared, which means that sharing
2375                  * is enabled for its class and its
2376                  * context is sharable (and it's not a
2377                  * generic method).
2378                  */
2379                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2380                         pass_vtable = TRUE;
2381         }
2382
2383         if (mini_method_get_context (cmethod) &&
2384                 mini_method_get_context (cmethod)->method_inst) {
2385                 g_assert (!pass_vtable);
2386
2387                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2388                         pass_mrgctx = TRUE;
2389                 } else {
2390                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2391                         MonoGenericContext *context = mini_method_get_context (cmethod);
2392                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2393
2394                         if (sharing_enabled && context_sharable)
2395                                 pass_mrgctx = TRUE;
2396                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2397                                 pass_mrgctx = TRUE;
2398                 }
2399         }
2400
2401         if (out_pass_vtable)
2402                 *out_pass_vtable = pass_vtable;
2403         if (out_pass_mrgctx)
2404                 *out_pass_mrgctx = pass_mrgctx;
2405 }
2406
2407 inline static MonoCallInst *
2408 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2409                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2410 {
2411         MonoCallInst *call;
2412 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2413         int i;
2414 #endif
2415
2416         if (tail)
2417                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2418         else
2419                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2420
2421         call->args = args;
2422         call->signature = sig;
2423         call->rgctx_reg = rgctx;
2424
2425         type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
2426
2427         if (tail) {
2428                 if (mini_type_is_vtype (cfg, sig->ret)) {
2429                         call->vret_var = cfg->vret_addr;
2430                         //g_assert_not_reached ();
2431                 }
2432         } else if (mini_type_is_vtype (cfg, sig->ret)) {
2433                 MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
2434                 MonoInst *loada;
2435
2436                 temp->backend.is_pinvoke = sig->pinvoke;
2437
2438                 /*
2439                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2440                  * address of return value to increase optimization opportunities.
2441                  * Before vtype decomposition, the dreg of the call ins itself represents the
2442                  * fact the call modifies the return value. After decomposition, the call will
2443                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2444                  * will be transformed into an LDADDR.
2445                  */
2446                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2447                 loada->dreg = alloc_preg (cfg);
2448                 loada->inst_p0 = temp;
2449                 /* We reference the call too since call->dreg could change during optimization */
2450                 loada->inst_p1 = call;
2451                 MONO_ADD_INS (cfg->cbb, loada);
2452
2453                 call->inst.dreg = temp->dreg;
2454
2455                 call->vret_var = loada;
2456         } else if (!MONO_TYPE_IS_VOID (sig->ret))
2457                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2458
2459 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2460         if (COMPILE_SOFT_FLOAT (cfg)) {
2461                 /* 
2462                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2463                  * an icall, but that cannot be done during the call sequence since it would clobber
2464                  * the call registers + the stack. So we do it before emitting the call.
2465                  */
2466                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2467                         MonoType *t;
2468                         MonoInst *in = call->args [i];
2469
2470                         if (i >= sig->hasthis)
2471                                 t = sig->params [i - sig->hasthis];
2472                         else
2473                                 t = &mono_defaults.int_class->byval_arg;
2474                         t = mono_type_get_underlying_type (t);
2475
2476                         if (!t->byref && t->type == MONO_TYPE_R4) {
2477                                 MonoInst *iargs [1];
2478                                 MonoInst *conv;
2479
2480                                 iargs [0] = in;
2481                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2482
2483                                 /* The result will be in an int vreg */
2484                                 call->args [i] = conv;
2485                         }
2486                 }
2487         }
2488 #endif
2489
2490         call->need_unbox_trampoline = unbox_trampoline;
2491
2492 #ifdef ENABLE_LLVM
2493         if (COMPILE_LLVM (cfg))
2494                 mono_llvm_emit_call (cfg, call);
2495         else
2496                 mono_arch_emit_call (cfg, call);
2497 #else
2498         mono_arch_emit_call (cfg, call);
2499 #endif
2500
2501         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2502         cfg->flags |= MONO_CFG_HAS_CALLS;
2503         
2504         return call;
2505 }
2506
2507 static void
2508 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2509 {
2510 #ifdef MONO_ARCH_RGCTX_REG
2511         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2512         cfg->uses_rgctx_reg = TRUE;
2513         call->rgctx_reg = TRUE;
2514 #ifdef ENABLE_LLVM
2515         call->rgctx_arg_reg = rgctx_reg;
2516 #endif
2517 #else
2518         NOT_IMPLEMENTED;
2519 #endif
2520 }       
2521
2522 inline static MonoInst*
2523 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2524 {
2525         MonoCallInst *call;
2526         int rgctx_reg = -1;
2527
2528         if (rgctx_arg) {
2529                 rgctx_reg = mono_alloc_preg (cfg);
2530                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2531         }
2532
2533         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2534
2535         call->inst.sreg1 = addr->dreg;
2536
2537         if (imt_arg)
2538                 emit_imt_argument (cfg, call, NULL, imt_arg);
2539
2540         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2541
2542         if (rgctx_arg)
2543                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2544
2545         return (MonoInst*)call;
2546 }
2547
2548 static MonoInst*
2549 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2550
2551 static MonoInst*
2552 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2553 static MonoInst*
2554 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2555
2556 static MonoInst*
2557 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2558                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2559 {
2560 #ifndef DISABLE_REMOTING
2561         gboolean might_be_remote = FALSE;
2562 #endif
2563         gboolean virtual = this != NULL;
2564         gboolean enable_for_aot = TRUE;
2565         int context_used;
2566         MonoCallInst *call;
2567         int rgctx_reg = 0;
2568         gboolean need_unbox_trampoline;
2569
2570         if (!sig)
2571                 sig = mono_method_signature (method);
2572
2573         if (rgctx_arg) {
2574                 rgctx_reg = mono_alloc_preg (cfg);
2575                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2576         }
2577
2578         if (method->string_ctor) {
2579                 /* Create the real signature */
2580                 /* FIXME: Cache these */
2581                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2582                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2583
2584                 sig = ctor_sig;
2585         }
2586
2587         context_used = mini_method_check_context_used (cfg, method);
2588
2589 #ifndef DISABLE_REMOTING
2590         might_be_remote = this && sig->hasthis &&
2591                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2592                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2593
2594         if (might_be_remote && context_used) {
2595                 MonoInst *addr;
2596
2597                 g_assert (cfg->generic_sharing_context);
2598
2599                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2600
2601                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2602         }
2603 #endif
2604
2605         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2606
2607         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2608
2609 #ifndef DISABLE_REMOTING
2610         if (might_be_remote)
2611                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2612         else
2613 #endif
2614                 call->method = method;
2615         call->inst.flags |= MONO_INST_HAS_METHOD;
2616         call->inst.inst_left = this;
2617         call->tail_call = tail;
2618
2619         if (virtual) {
2620                 int vtable_reg, slot_reg, this_reg;
2621                 int offset;
2622
2623                 this_reg = this->dreg;
2624
2625                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2626                         MonoInst *dummy_use;
2627
2628                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2629
2630                         /* Make a call to delegate->invoke_impl */
2631                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2632                         call->inst.inst_basereg = this_reg;
2633                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2634                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2635
2636                         /* We must emit a dummy use here because the delegate trampoline will
2637                         replace the 'this' argument with the delegate target making this activation
2638                         no longer a root for the delegate.
2639                         This is an issue for delegates that target collectible code such as dynamic
2640                         methods of GC'able assemblies.
2641
2642                         For a test case look into #667921.
2643
2644                         FIXME: a dummy use is not the best way to do it as the local register allocator
2645                         will put it on a caller save register and spil it around the call. 
2646                         Ideally, we would either put it on a callee save register or only do the store part.  
2647                          */
2648                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2649
2650                         return (MonoInst*)call;
2651                 }
2652
2653                 if ((!cfg->compile_aot || enable_for_aot) && 
2654                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2655                          (MONO_METHOD_IS_FINAL (method) &&
2656                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2657                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2658                         /* 
2659                          * the method is not virtual, we just need to ensure this is not null
2660                          * and then we can call the method directly.
2661                          */
2662 #ifndef DISABLE_REMOTING
2663                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2664                                 /* 
2665                                  * The check above ensures method is not gshared, this is needed since
2666                                  * gshared methods can't have wrappers.
2667                                  */
2668                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2669                         }
2670 #endif
2671
2672                         if (!method->string_ctor)
2673                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2674
2675                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2676                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2677                         /*
2678                          * the method is virtual, but we can statically dispatch since either
2679                          * it's class or the method itself are sealed.
2680                          * But first we need to ensure it's not a null reference.
2681                          */
2682                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2683
2684                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2685                 } else {
2686                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2687
2688                         vtable_reg = alloc_preg (cfg);
2689                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2690                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2691                                 slot_reg = -1;
2692 #ifdef MONO_ARCH_HAVE_IMT
2693                                 if (mono_use_imt) {
2694                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2695                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2696                                         slot_reg = vtable_reg;
2697                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2698                                 }
2699 #endif
2700                                 if (slot_reg == -1) {
2701                                         slot_reg = alloc_preg (cfg);
2702                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2703                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2704                                 }
2705                         } else {
2706                                 slot_reg = vtable_reg;
2707                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2708                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2709 #ifdef MONO_ARCH_HAVE_IMT
2710                                 if (imt_arg) {
2711                                         g_assert (mono_method_signature (method)->generic_param_count);
2712                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2713                                 }
2714 #endif
2715                         }
2716
2717                         call->inst.sreg1 = slot_reg;
2718                         call->inst.inst_offset = offset;
2719                         call->virtual = TRUE;
2720                 }
2721         }
2722
2723         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2724
2725         if (rgctx_arg)
2726                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2727
2728         return (MonoInst*)call;
2729 }
2730
2731 MonoInst*
2732 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2733 {
2734         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2735 }
2736
2737 MonoInst*
2738 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2739                                            MonoInst **args)
2740 {
2741         MonoCallInst *call;
2742
2743         g_assert (sig);
2744
2745         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2746         call->fptr = func;
2747
2748         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2749
2750         return (MonoInst*)call;
2751 }
2752
2753 MonoInst*
2754 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2755 {
2756         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2757
2758         g_assert (info);
2759
2760         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2761 }
2762
2763 /*
2764  * mono_emit_abs_call:
2765  *
2766  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2767  */
2768 inline static MonoInst*
2769 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2770                                         MonoMethodSignature *sig, MonoInst **args)
2771 {
2772         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2773         MonoInst *ins;
2774
2775         /* 
2776          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2777          * handle it.
2778          */
2779         if (cfg->abs_patches == NULL)
2780                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2781         g_hash_table_insert (cfg->abs_patches, ji, ji);
2782         ins = mono_emit_native_call (cfg, ji, sig, args);
2783         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2784         return ins;
2785 }
2786  
2787 static MonoInst*
2788 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2789 {
2790         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2791                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2792                         int widen_op = -1;
2793
2794                         /* 
2795                          * Native code might return non register sized integers 
2796                          * without initializing the upper bits.
2797                          */
2798                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2799                         case OP_LOADI1_MEMBASE:
2800                                 widen_op = OP_ICONV_TO_I1;
2801                                 break;
2802                         case OP_LOADU1_MEMBASE:
2803                                 widen_op = OP_ICONV_TO_U1;
2804                                 break;
2805                         case OP_LOADI2_MEMBASE:
2806                                 widen_op = OP_ICONV_TO_I2;
2807                                 break;
2808                         case OP_LOADU2_MEMBASE:
2809                                 widen_op = OP_ICONV_TO_U2;
2810                                 break;
2811                         default:
2812                                 break;
2813                         }
2814
2815                         if (widen_op != -1) {
2816                                 int dreg = alloc_preg (cfg);
2817                                 MonoInst *widen;
2818
2819                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2820                                 widen->type = ins->type;
2821                                 ins = widen;
2822                         }
2823                 }
2824         }
2825
2826         return ins;
2827 }
2828
2829 static MonoMethod*
2830 get_memcpy_method (void)
2831 {
2832         static MonoMethod *memcpy_method = NULL;
2833         if (!memcpy_method) {
2834                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2835                 if (!memcpy_method)
2836                         g_error ("Old corlib found. Install a new one");
2837         }
2838         return memcpy_method;
2839 }
2840
2841 static void
2842 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2843 {
2844         MonoClassField *field;
2845         gpointer iter = NULL;
2846
2847         while ((field = mono_class_get_fields (klass, &iter))) {
2848                 int foffset;
2849
2850                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2851                         continue;
2852                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2853                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2854                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2855                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2856                 } else {
2857                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2858                         if (field_class->has_references)
2859                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2860                 }
2861         }
2862 }
2863
2864 static void
2865 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2866 {
2867         int card_table_shift_bits;
2868         gpointer card_table_mask;
2869         guint8 *card_table;
2870         MonoInst *dummy_use;
2871         int nursery_shift_bits;
2872         size_t nursery_size;
2873         gboolean has_card_table_wb = FALSE;
2874
2875         if (!cfg->gen_write_barriers)
2876                 return;
2877
2878         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2879
2880         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2881
2882 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2883         has_card_table_wb = TRUE;
2884 #endif
2885
2886         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) {
2887                 MonoInst *wbarrier;
2888
2889                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2890                 wbarrier->sreg1 = ptr->dreg;
2891                 wbarrier->sreg2 = value->dreg;
2892                 MONO_ADD_INS (cfg->cbb, wbarrier);
2893         } else if (card_table) {
2894                 int offset_reg = alloc_preg (cfg);
2895                 int card_reg  = alloc_preg (cfg);
2896                 MonoInst *ins;
2897
2898                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2899                 if (card_table_mask)
2900                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2901
2902                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2903                  * IMM's larger than 32bits.
2904                  */
2905                 if (cfg->compile_aot) {
2906                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2907                 } else {
2908                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2909                         ins->inst_p0 = card_table;
2910                         ins->dreg = card_reg;
2911                         MONO_ADD_INS (cfg->cbb, ins);
2912                 }
2913
2914                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2915                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2916         } else {
2917                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2918                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2919         }
2920
2921         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2922 }
2923
2924 static gboolean
2925 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2926 {
2927         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2928         unsigned need_wb = 0;
2929
2930         if (align == 0)
2931                 align = 4;
2932
2933         /*types with references can't have alignment smaller than sizeof(void*) */
2934         if (align < SIZEOF_VOID_P)
2935                 return FALSE;
2936
2937         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2938         if (size > 32 * SIZEOF_VOID_P)
2939                 return FALSE;
2940
2941         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
2942
2943         /* We don't unroll more than 5 stores to avoid code bloat. */
2944         if (size > 5 * SIZEOF_VOID_P) {
2945                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2946                 size += (SIZEOF_VOID_P - 1);
2947                 size &= ~(SIZEOF_VOID_P - 1);
2948
2949                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2950                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2951                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2952                 return TRUE;
2953         }
2954
2955         destreg = iargs [0]->dreg;
2956         srcreg = iargs [1]->dreg;
2957         offset = 0;
2958
2959         dest_ptr_reg = alloc_preg (cfg);
2960         tmp_reg = alloc_preg (cfg);
2961
2962         /*tmp = dreg*/
2963         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
2964
2965         while (size >= SIZEOF_VOID_P) {
2966                 MonoInst *load_inst;
2967                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
2968                 load_inst->dreg = tmp_reg;
2969                 load_inst->inst_basereg = srcreg;
2970                 load_inst->inst_offset = offset;
2971                 MONO_ADD_INS (cfg->cbb, load_inst);
2972
2973                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
2974
2975                 if (need_wb & 0x1)
2976                         emit_write_barrier (cfg, iargs [0], load_inst);
2977
2978                 offset += SIZEOF_VOID_P;
2979                 size -= SIZEOF_VOID_P;
2980                 need_wb >>= 1;
2981
2982                 /*tmp += sizeof (void*)*/
2983                 if (size >= SIZEOF_VOID_P) {
2984                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
2985                         MONO_ADD_INS (cfg->cbb, iargs [0]);
2986                 }
2987         }
2988
2989         /* Those cannot be references since size < sizeof (void*) */
2990         while (size >= 4) {
2991                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
2992                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
2993                 offset += 4;
2994                 size -= 4;
2995         }
2996
2997         while (size >= 2) {
2998                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
2999                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3000                 offset += 2;
3001                 size -= 2;
3002         }
3003
3004         while (size >= 1) {
3005                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3006                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3007                 offset += 1;
3008                 size -= 1;
3009         }
3010
3011         return TRUE;
3012 }
3013
3014 /*
3015  * Emit code to copy a valuetype of type @klass whose address is stored in
3016  * @src->dreg to memory whose address is stored at @dest->dreg.
3017  */
3018 void
3019 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3020 {
3021         MonoInst *iargs [4];
3022         int context_used, n;
3023         guint32 align = 0;
3024         MonoMethod *memcpy_method;
3025         MonoInst *size_ins = NULL;
3026         MonoInst *memcpy_ins = NULL;
3027
3028         g_assert (klass);
3029         /*
3030          * This check breaks with spilled vars... need to handle it during verification anyway.
3031          * g_assert (klass && klass == src->klass && klass == dest->klass);
3032          */
3033
3034         if (mini_is_gsharedvt_klass (cfg, klass)) {
3035                 g_assert (!native);
3036                 context_used = mini_class_check_context_used (cfg, klass);
3037                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3038                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3039         }
3040
3041         if (native)
3042                 n = mono_class_native_size (klass, &align);
3043         else
3044                 n = mono_class_value_size (klass, &align);
3045
3046         /* if native is true there should be no references in the struct */
3047         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3048                 /* Avoid barriers when storing to the stack */
3049                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3050                           (dest->opcode == OP_LDADDR))) {
3051                         int context_used;
3052
3053                         iargs [0] = dest;
3054                         iargs [1] = src;
3055
3056                         context_used = mini_class_check_context_used (cfg, klass);
3057
3058                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3059                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3060                                 return;
3061                         } else if (context_used) {
3062                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3063                         }  else {
3064                                 if (cfg->compile_aot) {
3065                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3066                                 } else {
3067                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3068                                         mono_class_compute_gc_descriptor (klass);
3069                                 }
3070                         }
3071
3072                         if (size_ins)
3073                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3074                         else
3075                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3076                         return;
3077                 }
3078         }
3079
3080         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3081                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3082                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3083         } else {
3084                 iargs [0] = dest;
3085                 iargs [1] = src;
3086                 if (size_ins)
3087                         iargs [2] = size_ins;
3088                 else
3089                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3090                 
3091                 memcpy_method = get_memcpy_method ();
3092                 if (memcpy_ins)
3093                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3094                 else
3095                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3096         }
3097 }
3098
3099 static MonoMethod*
3100 get_memset_method (void)
3101 {
3102         static MonoMethod *memset_method = NULL;
3103         if (!memset_method) {
3104                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3105                 if (!memset_method)
3106                         g_error ("Old corlib found. Install a new one");
3107         }
3108         return memset_method;
3109 }
3110
3111 void
3112 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3113 {
3114         MonoInst *iargs [3];
3115         int n, context_used;
3116         guint32 align;
3117         MonoMethod *memset_method;
3118         MonoInst *size_ins = NULL;
3119         MonoInst *bzero_ins = NULL;
3120         static MonoMethod *bzero_method;
3121
3122         /* FIXME: Optimize this for the case when dest is an LDADDR */
3123
3124         mono_class_init (klass);
3125         if (mini_is_gsharedvt_klass (cfg, klass)) {
3126                 context_used = mini_class_check_context_used (cfg, klass);
3127                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3128                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3129                 if (!bzero_method)
3130                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3131                 g_assert (bzero_method);
3132                 iargs [0] = dest;
3133                 iargs [1] = size_ins;
3134                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3135                 return;
3136         }
3137
3138         n = mono_class_value_size (klass, &align);
3139
3140         if (n <= sizeof (gpointer) * 5) {
3141                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3142         }
3143         else {
3144                 memset_method = get_memset_method ();
3145                 iargs [0] = dest;
3146                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3147                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3148                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3149         }
3150 }
3151
3152 static MonoInst*
3153 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3154 {
3155         MonoInst *this = NULL;
3156
3157         g_assert (cfg->generic_sharing_context);
3158
3159         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3160                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3161                         !method->klass->valuetype)
3162                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3163
3164         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3165                 MonoInst *mrgctx_loc, *mrgctx_var;
3166
3167                 g_assert (!this);
3168                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3169
3170                 mrgctx_loc = mono_get_vtable_var (cfg);
3171                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3172
3173                 return mrgctx_var;
3174         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3175                 MonoInst *vtable_loc, *vtable_var;
3176
3177                 g_assert (!this);
3178
3179                 vtable_loc = mono_get_vtable_var (cfg);
3180                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3181
3182                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3183                         MonoInst *mrgctx_var = vtable_var;
3184                         int vtable_reg;
3185
3186                         vtable_reg = alloc_preg (cfg);
3187                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3188                         vtable_var->type = STACK_PTR;
3189                 }
3190
3191                 return vtable_var;
3192         } else {
3193                 MonoInst *ins;
3194                 int vtable_reg;
3195         
3196                 vtable_reg = alloc_preg (cfg);
3197                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3198                 return ins;
3199         }
3200 }
3201
3202 static MonoJumpInfoRgctxEntry *
3203 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3204 {
3205         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3206         res->method = method;
3207         res->in_mrgctx = in_mrgctx;
3208         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3209         res->data->type = patch_type;
3210         res->data->data.target = patch_data;
3211         res->info_type = info_type;
3212
3213         return res;
3214 }
3215
3216 static inline MonoInst*
3217 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3218 {
3219         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3220 }
3221
3222 static MonoInst*
3223 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3224                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3225 {
3226         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);
3227         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3228
3229         return emit_rgctx_fetch (cfg, rgctx, entry);
3230 }
3231
3232 static MonoInst*
3233 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3234                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3235 {
3236         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);
3237         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3238
3239         return emit_rgctx_fetch (cfg, rgctx, entry);
3240 }
3241
3242 static MonoInst*
3243 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3244                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3245 {
3246         MonoJumpInfoGSharedVtCall *call_info;
3247         MonoJumpInfoRgctxEntry *entry;
3248         MonoInst *rgctx;
3249
3250         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3251         call_info->sig = sig;
3252         call_info->method = cmethod;
3253
3254         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);
3255         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3256
3257         return emit_rgctx_fetch (cfg, rgctx, entry);
3258 }
3259
3260
3261 static MonoInst*
3262 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3263                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3264 {
3265         MonoJumpInfoRgctxEntry *entry;
3266         MonoInst *rgctx;
3267
3268         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);
3269         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3270
3271         return emit_rgctx_fetch (cfg, rgctx, entry);
3272 }
3273
3274 /*
3275  * emit_get_rgctx_method:
3276  *
3277  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3278  * normal constants, else emit a load from the rgctx.
3279  */
3280 static MonoInst*
3281 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3282                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3283 {
3284         if (!context_used) {
3285                 MonoInst *ins;
3286
3287                 switch (rgctx_type) {
3288                 case MONO_RGCTX_INFO_METHOD:
3289                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3290                         return ins;
3291                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3292                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3293                         return ins;
3294                 default:
3295                         g_assert_not_reached ();
3296                 }
3297         } else {
3298                 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);
3299                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3300
3301                 return emit_rgctx_fetch (cfg, rgctx, entry);
3302         }
3303 }
3304
3305 static MonoInst*
3306 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3307                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3308 {
3309         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);
3310         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3311
3312         return emit_rgctx_fetch (cfg, rgctx, entry);
3313 }
3314
3315 static int
3316 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3317 {
3318         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3319         MonoRuntimeGenericContextInfoTemplate *template;
3320         int i, idx;
3321
3322         g_assert (info);
3323
3324         for (i = 0; i < info->entries->len; ++i) {
3325                 MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (info->entries, i);
3326
3327                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3328                         return i;
3329         }
3330
3331         template = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate));
3332         template->info_type = rgctx_type;
3333         template->data = data;
3334
3335         idx = info->entries->len;
3336
3337         g_ptr_array_add (info->entries, template);
3338
3339         return idx;
3340 }
3341
3342 /*
3343  * emit_get_gsharedvt_info:
3344  *
3345  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3346  */
3347 static MonoInst*
3348 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3349 {
3350         MonoInst *ins;
3351         int idx, dreg;
3352
3353         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3354         /* Load info->entries [idx] */
3355         dreg = alloc_preg (cfg);
3356         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3357
3358         return ins;
3359 }
3360
3361 static MonoInst*
3362 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3363 {
3364         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3365 }
3366
3367 /*
3368  * On return the caller must check @klass for load errors.
3369  */
3370 static void
3371 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3372 {
3373         MonoInst *vtable_arg;
3374         MonoCallInst *call;
3375         int context_used;
3376
3377         context_used = mini_class_check_context_used (cfg, klass);
3378
3379         if (context_used) {
3380                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3381                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3382         } else {
3383                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3384
3385                 if (!vtable)
3386                         return;
3387                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3388         }
3389
3390         if (COMPILE_LLVM (cfg))
3391                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3392         else
3393                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3394 #ifdef MONO_ARCH_VTABLE_REG
3395         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3396         cfg->uses_vtable_reg = TRUE;
3397 #else
3398         NOT_IMPLEMENTED;
3399 #endif
3400 }
3401
3402 static void
3403 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc)
3404 {
3405         MonoInst *ins;
3406
3407         if (cfg->gen_seq_points && cfg->method == method) {
3408                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3409                 MONO_ADD_INS (cfg->cbb, ins);
3410         }
3411 }
3412
3413 static void
3414 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
3415 {
3416         if (mini_get_debug_options ()->better_cast_details) {
3417                 int to_klass_reg = alloc_preg (cfg);
3418                 int vtable_reg = alloc_preg (cfg);
3419                 int klass_reg = alloc_preg (cfg);
3420                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3421
3422                 if (!tls_get) {
3423                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3424                         exit (1);
3425                 }
3426
3427                 MONO_ADD_INS (cfg->cbb, tls_get);
3428                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3429                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3430
3431                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3432                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3433                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3434         }
3435 }
3436
3437 static void
3438 reset_cast_details (MonoCompile *cfg)
3439 {
3440         /* Reset the variables holding the cast details */
3441         if (mini_get_debug_options ()->better_cast_details) {
3442                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3443
3444                 MONO_ADD_INS (cfg->cbb, tls_get);
3445                 /* It is enough to reset the from field */
3446                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3447         }
3448 }
3449
3450 /*
3451  * On return the caller must check @array_class for load errors
3452  */
3453 static void
3454 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3455 {
3456         int vtable_reg = alloc_preg (cfg);
3457         int context_used;
3458
3459         context_used = mini_class_check_context_used (cfg, array_class);
3460
3461         save_cast_details (cfg, array_class, obj->dreg);
3462
3463         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3464
3465         if (cfg->opt & MONO_OPT_SHARED) {
3466                 int class_reg = alloc_preg (cfg);
3467                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3468                 if (cfg->compile_aot) {
3469                         int klass_reg = alloc_preg (cfg);
3470                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3471                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3472                 } else {
3473                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3474                 }
3475         } else if (context_used) {
3476                 MonoInst *vtable_ins;
3477
3478                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3479                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3480         } else {
3481                 if (cfg->compile_aot) {
3482                         int vt_reg;
3483                         MonoVTable *vtable;
3484
3485                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3486                                 return;
3487                         vt_reg = alloc_preg (cfg);
3488                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3489                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3490                 } else {
3491                         MonoVTable *vtable;
3492                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3493                                 return;
3494                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3495                 }
3496         }
3497         
3498         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3499
3500         reset_cast_details (cfg);
3501 }
3502
3503 /**
3504  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3505  * generic code is generated.
3506  */
3507 static MonoInst*
3508 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3509 {
3510         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3511
3512         if (context_used) {
3513                 MonoInst *rgctx, *addr;
3514
3515                 /* FIXME: What if the class is shared?  We might not
3516                    have to get the address of the method from the
3517                    RGCTX. */
3518                 addr = emit_get_rgctx_method (cfg, context_used, method,
3519                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3520
3521                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3522
3523                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3524         } else {
3525                 gboolean pass_vtable, pass_mrgctx;
3526                 MonoInst *rgctx_arg = NULL;
3527
3528                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3529                 g_assert (!pass_mrgctx);
3530
3531                 if (pass_vtable) {
3532                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3533
3534                         g_assert (vtable);
3535                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3536                 }
3537
3538                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3539         }
3540 }
3541
3542 static MonoInst*
3543 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3544 {
3545         MonoInst *add;
3546         int obj_reg;
3547         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3548         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3549         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3550         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3551
3552         obj_reg = sp [0]->dreg;
3553         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3554         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3555
3556         /* FIXME: generics */
3557         g_assert (klass->rank == 0);
3558                         
3559         // Check rank == 0
3560         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3561         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3562
3563         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3564         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3565
3566         if (context_used) {
3567                 MonoInst *element_class;
3568
3569                 /* This assertion is from the unboxcast insn */
3570                 g_assert (klass->rank == 0);
3571
3572                 element_class = emit_get_rgctx_klass (cfg, context_used,
3573                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3574
3575                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3576                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3577         } else {
3578                 save_cast_details (cfg, klass->element_class, obj_reg);
3579                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3580                 reset_cast_details (cfg);
3581         }
3582
3583         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3584         MONO_ADD_INS (cfg->cbb, add);
3585         add->type = STACK_MP;
3586         add->klass = klass;
3587
3588         return add;
3589 }
3590
3591 static MonoInst*
3592 handle_unbox_gsharedvt (MonoCompile *cfg, int context_used, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3593 {
3594         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3595         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3596         MonoInst *ins;
3597         int dreg, addr_reg;
3598
3599         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3600
3601         /* obj */
3602         args [0] = obj;
3603
3604         /* klass */
3605         args [1] = klass_inst;
3606
3607         /* CASTCLASS */
3608         obj = mono_emit_jit_icall (cfg, mono_object_castclass, args);
3609
3610         NEW_BBLOCK (cfg, is_ref_bb);
3611         NEW_BBLOCK (cfg, is_nullable_bb);
3612         NEW_BBLOCK (cfg, end_bb);
3613         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3614         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3615         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3616
3617         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3618         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3619
3620         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3621         addr_reg = alloc_dreg (cfg, STACK_MP);
3622
3623         /* Non-ref case */
3624         /* UNBOX */
3625         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3626         MONO_ADD_INS (cfg->cbb, addr);
3627
3628         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3629
3630         /* Ref case */
3631         MONO_START_BB (cfg, is_ref_bb);
3632
3633         /* Save the ref to a temporary */
3634         dreg = alloc_ireg (cfg);
3635         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3636         addr->dreg = addr_reg;
3637         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3638         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3639
3640         /* Nullable case */
3641         MONO_START_BB (cfg, is_nullable_bb);
3642
3643         {
3644                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3645                 MonoInst *unbox_call;
3646                 MonoMethodSignature *unbox_sig;
3647                 MonoInst *var;
3648
3649                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3650
3651                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3652                 unbox_sig->ret = &klass->byval_arg;
3653                 unbox_sig->param_count = 1;
3654                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3655                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3656
3657                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3658                 addr->dreg = addr_reg;
3659         }
3660
3661         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3662
3663         /* End */
3664         MONO_START_BB (cfg, end_bb);
3665
3666         /* LDOBJ */
3667         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3668
3669         *out_cbb = cfg->cbb;
3670
3671         return ins;
3672 }
3673
3674 /*
3675  * Returns NULL and set the cfg exception on error.
3676  */
3677 static MonoInst*
3678 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3679 {
3680         MonoInst *iargs [2];
3681         void *alloc_ftn;
3682
3683         if (context_used) {
3684                 MonoInst *data;
3685                 int rgctx_info;
3686                 MonoInst *iargs [2];
3687
3688                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3689
3690                 if (cfg->opt & MONO_OPT_SHARED)
3691                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3692                 else
3693                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3694                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3695
3696                 if (cfg->opt & MONO_OPT_SHARED) {
3697                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3698                         iargs [1] = data;
3699                         alloc_ftn = mono_object_new;
3700                 } else {
3701                         iargs [0] = data;
3702                         alloc_ftn = mono_object_new_specific;
3703                 }
3704
3705                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3706                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3707
3708                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3709         }
3710
3711         if (cfg->opt & MONO_OPT_SHARED) {
3712                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3713                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3714
3715                 alloc_ftn = mono_object_new;
3716         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3717                 /* This happens often in argument checking code, eg. throw new FooException... */
3718                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3719                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3720                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3721         } else {
3722                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3723                 MonoMethod *managed_alloc = NULL;
3724                 gboolean pass_lw;
3725
3726                 if (!vtable) {
3727                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3728                         cfg->exception_ptr = klass;
3729                         return NULL;
3730                 }
3731
3732 #ifndef MONO_CROSS_COMPILE
3733                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3734 #endif
3735
3736                 if (managed_alloc) {
3737                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3738                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3739                 }
3740                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3741                 if (pass_lw) {
3742                         guint32 lw = vtable->klass->instance_size;
3743                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3744                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3745                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3746                 }
3747                 else {
3748                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3749                 }
3750         }
3751
3752         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3753 }
3754         
3755 /*
3756  * Returns NULL and set the cfg exception on error.
3757  */     
3758 static MonoInst*
3759 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3760 {
3761         MonoInst *alloc, *ins;
3762
3763         *out_cbb = cfg->cbb;
3764
3765         if (mono_class_is_nullable (klass)) {
3766                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3767
3768                 if (context_used) {
3769                         /* FIXME: What if the class is shared?  We might not
3770                            have to get the method address from the RGCTX. */
3771                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3772                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3773                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3774
3775                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3776                 } else {
3777                         gboolean pass_vtable, pass_mrgctx;
3778                         MonoInst *rgctx_arg = NULL;
3779
3780                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3781                         g_assert (!pass_mrgctx);
3782
3783                         if (pass_vtable) {
3784                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3785
3786                                 g_assert (vtable);
3787                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3788                         }
3789
3790                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3791                 }
3792         }
3793
3794         if (mini_is_gsharedvt_klass (cfg, klass)) {
3795                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3796                 MonoInst *res, *is_ref, *src_var, *addr;
3797                 int addr_reg, dreg;
3798
3799                 dreg = alloc_ireg (cfg);
3800
3801                 NEW_BBLOCK (cfg, is_ref_bb);
3802                 NEW_BBLOCK (cfg, is_nullable_bb);
3803                 NEW_BBLOCK (cfg, end_bb);
3804                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3805                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3806                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3807
3808                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3809                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3810
3811                 /* Non-ref case */
3812                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3813                 if (!alloc)
3814                         return NULL;
3815                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3816                 ins->opcode = OP_STOREV_MEMBASE;
3817
3818                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3819                 res->type = STACK_OBJ;
3820                 res->klass = klass;
3821                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3822                 
3823                 /* Ref case */
3824                 MONO_START_BB (cfg, is_ref_bb);
3825                 addr_reg = alloc_ireg (cfg);
3826
3827                 /* val is a vtype, so has to load the value manually */
3828                 src_var = get_vreg_to_inst (cfg, val->dreg);
3829                 if (!src_var)
3830                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3831                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3832                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3833                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3834
3835                 /* Nullable case */
3836                 MONO_START_BB (cfg, is_nullable_bb);
3837
3838                 {
3839                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3840                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3841                         MonoInst *box_call;
3842                         MonoMethodSignature *box_sig;
3843
3844                         /*
3845                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3846                          * construct that method at JIT time, so have to do things by hand.
3847                          */
3848                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3849                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3850                         box_sig->param_count = 1;
3851                         box_sig->params [0] = &klass->byval_arg;
3852                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3853                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3854                         res->type = STACK_OBJ;
3855                         res->klass = klass;
3856                 }
3857
3858                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3859
3860                 MONO_START_BB (cfg, end_bb);
3861
3862                 *out_cbb = cfg->cbb;
3863
3864                 return res;
3865         } else {
3866                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3867                 if (!alloc)
3868                         return NULL;
3869
3870                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3871                 return alloc;
3872         }
3873 }
3874
3875
3876 static gboolean
3877 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3878 {
3879         int i;
3880         MonoGenericContainer *container;
3881         MonoGenericInst *ginst;
3882
3883         if (klass->generic_class) {
3884                 container = klass->generic_class->container_class->generic_container;
3885                 ginst = klass->generic_class->context.class_inst;
3886         } else if (klass->generic_container && context_used) {
3887                 container = klass->generic_container;
3888                 ginst = container->context.class_inst;
3889         } else {
3890                 return FALSE;
3891         }
3892
3893         for (i = 0; i < container->type_argc; ++i) {
3894                 MonoType *type;
3895                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
3896                         continue;
3897                 type = ginst->type_argv [i];
3898                 if (mini_type_is_reference (cfg, type))
3899                         return TRUE;
3900         }
3901         return FALSE;
3902 }
3903
3904 // FIXME: This doesn't work yet (class libs tests fail?)
3905 #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)
3906
3907 /*
3908  * Returns NULL and set the cfg exception on error.
3909  */
3910 static MonoInst*
3911 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3912 {
3913         MonoBasicBlock *is_null_bb;
3914         int obj_reg = src->dreg;
3915         int vtable_reg = alloc_preg (cfg);
3916         MonoInst *klass_inst = NULL;
3917
3918         if (context_used) {
3919                 MonoInst *args [3];
3920
3921                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
3922                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
3923                         MonoInst *cache_ins;
3924
3925                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3926
3927                         /* obj */
3928                         args [0] = src;
3929
3930                         /* klass - it's the second element of the cache entry*/
3931                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3932
3933                         /* cache */
3934                         args [2] = cache_ins;
3935
3936                         return mono_emit_method_call (cfg, mono_castclass, args, NULL);
3937                 }
3938
3939                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3940         }
3941
3942         NEW_BBLOCK (cfg, is_null_bb);
3943
3944         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3945         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3946
3947         save_cast_details (cfg, klass, obj_reg);
3948
3949         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3950                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3951                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
3952         } else {
3953                 int klass_reg = alloc_preg (cfg);
3954
3955                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3956
3957                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3958                         /* the remoting code is broken, access the class for now */
3959                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3960                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3961                                 if (!vt) {
3962                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3963                                         cfg->exception_ptr = klass;
3964                                         return NULL;
3965                                 }
3966                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3967                         } else {
3968                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3969                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3970                         }
3971                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3972                 } else {
3973                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3974                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
3975                 }
3976         }
3977
3978         MONO_START_BB (cfg, is_null_bb);
3979
3980         reset_cast_details (cfg);
3981
3982         return src;
3983 }
3984
3985 /*
3986  * Returns NULL and set the cfg exception on error.
3987  */
3988 static MonoInst*
3989 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3990 {
3991         MonoInst *ins;
3992         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
3993         int obj_reg = src->dreg;
3994         int vtable_reg = alloc_preg (cfg);
3995         int res_reg = alloc_ireg_ref (cfg);
3996         MonoInst *klass_inst = NULL;
3997
3998         if (context_used) {
3999                 MonoInst *args [3];
4000
4001                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4002                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4003                         MonoInst *cache_ins;
4004
4005                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4006
4007                         /* obj */
4008                         args [0] = src;
4009
4010                         /* klass - it's the second element of the cache entry*/
4011                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4012
4013                         /* cache */
4014                         args [2] = cache_ins;
4015
4016                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4017                 }
4018
4019                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4020         }
4021
4022         NEW_BBLOCK (cfg, is_null_bb);
4023         NEW_BBLOCK (cfg, false_bb);
4024         NEW_BBLOCK (cfg, end_bb);
4025
4026         /* Do the assignment at the beginning, so the other assignment can be if converted */
4027         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4028         ins->type = STACK_OBJ;
4029         ins->klass = klass;
4030
4031         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4032         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4033
4034         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4035
4036         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4037                 g_assert (!context_used);
4038                 /* the is_null_bb target simply copies the input register to the output */
4039                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4040         } else {
4041                 int klass_reg = alloc_preg (cfg);
4042
4043                 if (klass->rank) {
4044                         int rank_reg = alloc_preg (cfg);
4045                         int eclass_reg = alloc_preg (cfg);
4046
4047                         g_assert (!context_used);
4048                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4049                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4050                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4051                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4052                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
4053                         if (klass->cast_class == mono_defaults.object_class) {
4054                                 int parent_reg = alloc_preg (cfg);
4055                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4056                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4057                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4058                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4059                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4060                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4061                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4062                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4063                         } else if (klass->cast_class == mono_defaults.enum_class) {
4064                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4065                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4066                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4067                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4068                         } else {
4069                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4070                                         /* Check that the object is a vector too */
4071                                         int bounds_reg = alloc_preg (cfg);
4072                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4073                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4074                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4075                                 }
4076
4077                                 /* the is_null_bb target simply copies the input register to the output */
4078                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4079                         }
4080                 } else if (mono_class_is_nullable (klass)) {
4081                         g_assert (!context_used);
4082                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4083                         /* the is_null_bb target simply copies the input register to the output */
4084                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4085                 } else {
4086                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4087                                 g_assert (!context_used);
4088                                 /* the remoting code is broken, access the class for now */
4089                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4090                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4091                                         if (!vt) {
4092                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4093                                                 cfg->exception_ptr = klass;
4094                                                 return NULL;
4095                                         }
4096                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4097                                 } else {
4098                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4099                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4100                                 }
4101                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4102                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4103                         } else {
4104                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4105                                 /* the is_null_bb target simply copies the input register to the output */
4106                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4107                         }
4108                 }
4109         }
4110
4111         MONO_START_BB (cfg, false_bb);
4112
4113         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4114         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4115
4116         MONO_START_BB (cfg, is_null_bb);
4117
4118         MONO_START_BB (cfg, end_bb);
4119
4120         return ins;
4121 }
4122
4123 static MonoInst*
4124 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4125 {
4126         /* This opcode takes as input an object reference and a class, and returns:
4127         0) if the object is an instance of the class,
4128         1) if the object is not instance of the class,
4129         2) if the object is a proxy whose type cannot be determined */
4130
4131         MonoInst *ins;
4132 #ifndef DISABLE_REMOTING
4133         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4134 #else
4135         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4136 #endif
4137         int obj_reg = src->dreg;
4138         int dreg = alloc_ireg (cfg);
4139         int tmp_reg;
4140 #ifndef DISABLE_REMOTING
4141         int klass_reg = alloc_preg (cfg);
4142 #endif
4143
4144         NEW_BBLOCK (cfg, true_bb);
4145         NEW_BBLOCK (cfg, false_bb);
4146         NEW_BBLOCK (cfg, end_bb);
4147 #ifndef DISABLE_REMOTING
4148         NEW_BBLOCK (cfg, false2_bb);
4149         NEW_BBLOCK (cfg, no_proxy_bb);
4150 #endif
4151
4152         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4153         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4154
4155         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4156 #ifndef DISABLE_REMOTING
4157                 NEW_BBLOCK (cfg, interface_fail_bb);
4158 #endif
4159
4160                 tmp_reg = alloc_preg (cfg);
4161                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4162 #ifndef DISABLE_REMOTING
4163                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4164                 MONO_START_BB (cfg, interface_fail_bb);
4165                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4166                 
4167                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4168
4169                 tmp_reg = alloc_preg (cfg);
4170                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4171                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4172                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4173 #else
4174                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4175 #endif
4176         } else {
4177 #ifndef DISABLE_REMOTING
4178                 tmp_reg = alloc_preg (cfg);
4179                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4180                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4181
4182                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4183                 tmp_reg = alloc_preg (cfg);
4184                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4185                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4186
4187                 tmp_reg = alloc_preg (cfg);             
4188                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4189                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4190                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4191                 
4192                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4193                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4194
4195                 MONO_START_BB (cfg, no_proxy_bb);
4196
4197                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4198 #else
4199                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4200 #endif
4201         }
4202
4203         MONO_START_BB (cfg, false_bb);
4204
4205         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4206         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4207
4208 #ifndef DISABLE_REMOTING
4209         MONO_START_BB (cfg, false2_bb);
4210
4211         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4212         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4213 #endif
4214
4215         MONO_START_BB (cfg, true_bb);
4216
4217         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4218
4219         MONO_START_BB (cfg, end_bb);
4220
4221         /* FIXME: */
4222         MONO_INST_NEW (cfg, ins, OP_ICONST);
4223         ins->dreg = dreg;
4224         ins->type = STACK_I4;
4225
4226         return ins;
4227 }
4228
4229 static MonoInst*
4230 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4231 {
4232         /* This opcode takes as input an object reference and a class, and returns:
4233         0) if the object is an instance of the class,
4234         1) if the object is a proxy whose type cannot be determined
4235         an InvalidCastException exception is thrown otherwhise*/
4236         
4237         MonoInst *ins;
4238 #ifndef DISABLE_REMOTING
4239         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4240 #else
4241         MonoBasicBlock *ok_result_bb;
4242 #endif
4243         int obj_reg = src->dreg;
4244         int dreg = alloc_ireg (cfg);
4245         int tmp_reg = alloc_preg (cfg);
4246
4247 #ifndef DISABLE_REMOTING
4248         int klass_reg = alloc_preg (cfg);
4249         NEW_BBLOCK (cfg, end_bb);
4250 #endif
4251
4252         NEW_BBLOCK (cfg, ok_result_bb);
4253
4254         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4255         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4256
4257         save_cast_details (cfg, klass, obj_reg);
4258
4259         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4260 #ifndef DISABLE_REMOTING
4261                 NEW_BBLOCK (cfg, interface_fail_bb);
4262         
4263                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4264                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4265                 MONO_START_BB (cfg, interface_fail_bb);
4266                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4267
4268                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4269
4270                 tmp_reg = alloc_preg (cfg);             
4271                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4272                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4273                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4274                 
4275                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4276                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4277 #else
4278                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4279                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4280                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4281 #endif
4282         } else {
4283 #ifndef DISABLE_REMOTING
4284                 NEW_BBLOCK (cfg, no_proxy_bb);
4285
4286                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4287                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4288                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4289
4290                 tmp_reg = alloc_preg (cfg);
4291                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4292                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4293
4294                 tmp_reg = alloc_preg (cfg);
4295                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4296                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4297                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4298
4299                 NEW_BBLOCK (cfg, fail_1_bb);
4300                 
4301                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4302
4303                 MONO_START_BB (cfg, fail_1_bb);
4304
4305                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4306                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4307
4308                 MONO_START_BB (cfg, no_proxy_bb);
4309
4310                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4311 #else
4312                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4313 #endif
4314         }
4315
4316         MONO_START_BB (cfg, ok_result_bb);
4317
4318         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4319
4320 #ifndef DISABLE_REMOTING
4321         MONO_START_BB (cfg, end_bb);
4322 #endif
4323
4324         /* FIXME: */
4325         MONO_INST_NEW (cfg, ins, OP_ICONST);
4326         ins->dreg = dreg;
4327         ins->type = STACK_I4;
4328
4329         return ins;
4330 }
4331
4332 /*
4333  * Returns NULL and set the cfg exception on error.
4334  */
4335 static G_GNUC_UNUSED MonoInst*
4336 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4337 {
4338         MonoInst *ptr;
4339         int dreg;
4340         gpointer *trampoline;
4341         MonoInst *obj, *method_ins, *tramp_ins;
4342         MonoDomain *domain;
4343         guint8 **code_slot;
4344
4345         obj = handle_alloc (cfg, klass, FALSE, 0);
4346         if (!obj)
4347                 return NULL;
4348
4349         /* Inline the contents of mono_delegate_ctor */
4350
4351         /* Set target field */
4352         /* Optimize away setting of NULL target */
4353         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4354                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4355                 if (cfg->gen_write_barriers) {
4356                         dreg = alloc_preg (cfg);
4357                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4358                         emit_write_barrier (cfg, ptr, target);
4359                 }
4360         }
4361
4362         /* Set method field */
4363         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4364         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4365         if (cfg->gen_write_barriers) {
4366                 dreg = alloc_preg (cfg);
4367                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4368                 emit_write_barrier (cfg, ptr, method_ins);
4369         }
4370         /* 
4371          * To avoid looking up the compiled code belonging to the target method
4372          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4373          * store it, and we fill it after the method has been compiled.
4374          */
4375         if (!cfg->compile_aot && !method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4376                 MonoInst *code_slot_ins;
4377
4378                 if (context_used) {
4379                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4380                 } else {
4381                         domain = mono_domain_get ();
4382                         mono_domain_lock (domain);
4383                         if (!domain_jit_info (domain)->method_code_hash)
4384                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4385                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4386                         if (!code_slot) {
4387                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4388                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4389                         }
4390                         mono_domain_unlock (domain);
4391
4392                         EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4393                 }
4394                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4395         }
4396
4397         /* Set invoke_impl field */
4398         if (cfg->compile_aot) {
4399                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
4400         } else {
4401                 trampoline = mono_create_delegate_trampoline (cfg->domain, klass);
4402                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4403         }
4404         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4405
4406         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4407
4408         return obj;
4409 }
4410
4411 static MonoInst*
4412 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4413 {
4414         MonoJitICallInfo *info;
4415
4416         /* Need to register the icall so it gets an icall wrapper */
4417         info = mono_get_array_new_va_icall (rank);
4418
4419         cfg->flags |= MONO_CFG_HAS_VARARGS;
4420
4421         /* mono_array_new_va () needs a vararg calling convention */
4422         cfg->disable_llvm = TRUE;
4423
4424         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4425         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4426 }
4427
4428 static void
4429 mono_emit_load_got_addr (MonoCompile *cfg)
4430 {
4431         MonoInst *getaddr, *dummy_use;
4432
4433         if (!cfg->got_var || cfg->got_var_allocated)
4434                 return;
4435
4436         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4437         getaddr->cil_code = cfg->header->code;
4438         getaddr->dreg = cfg->got_var->dreg;
4439
4440         /* Add it to the start of the first bblock */
4441         if (cfg->bb_entry->code) {
4442                 getaddr->next = cfg->bb_entry->code;
4443                 cfg->bb_entry->code = getaddr;
4444         }
4445         else
4446                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4447
4448         cfg->got_var_allocated = TRUE;
4449
4450         /* 
4451          * Add a dummy use to keep the got_var alive, since real uses might
4452          * only be generated by the back ends.
4453          * Add it to end_bblock, so the variable's lifetime covers the whole
4454          * method.
4455          * It would be better to make the usage of the got var explicit in all
4456          * cases when the backend needs it (i.e. calls, throw etc.), so this
4457          * wouldn't be needed.
4458          */
4459         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4460         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4461 }
4462
4463 static int inline_limit;
4464 static gboolean inline_limit_inited;
4465
4466 static gboolean
4467 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4468 {
4469         MonoMethodHeaderSummary header;
4470         MonoVTable *vtable;
4471 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4472         MonoMethodSignature *sig = mono_method_signature (method);
4473         int i;
4474 #endif
4475
4476         if (cfg->generic_sharing_context)
4477                 return FALSE;
4478
4479         if (cfg->inline_depth > 10)
4480                 return FALSE;
4481
4482 #ifdef MONO_ARCH_HAVE_LMF_OPS
4483         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4484                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4485             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4486                 return TRUE;
4487 #endif
4488
4489
4490         if (!mono_method_get_header_summary (method, &header))
4491                 return FALSE;
4492
4493         /*runtime, icall and pinvoke are checked by summary call*/
4494         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4495             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4496             (mono_class_is_marshalbyref (method->klass)) ||
4497             header.has_clauses)
4498                 return FALSE;
4499
4500         /* also consider num_locals? */
4501         /* Do the size check early to avoid creating vtables */
4502         if (!inline_limit_inited) {
4503                 if (getenv ("MONO_INLINELIMIT"))
4504                         inline_limit = atoi (getenv ("MONO_INLINELIMIT"));
4505                 else
4506                         inline_limit = INLINE_LENGTH_LIMIT;
4507                 inline_limit_inited = TRUE;
4508         }
4509         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4510                 return FALSE;
4511
4512         /*
4513          * if we can initialize the class of the method right away, we do,
4514          * otherwise we don't allow inlining if the class needs initialization,
4515          * since it would mean inserting a call to mono_runtime_class_init()
4516          * inside the inlined code
4517          */
4518         if (!(cfg->opt & MONO_OPT_SHARED)) {
4519                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4520                         if (cfg->run_cctors && method->klass->has_cctor) {
4521                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4522                                 if (!method->klass->runtime_info)
4523                                         /* No vtable created yet */
4524                                         return FALSE;
4525                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4526                                 if (!vtable)
4527                                         return FALSE;
4528                                 /* This makes so that inline cannot trigger */
4529                                 /* .cctors: too many apps depend on them */
4530                                 /* running with a specific order... */
4531                                 if (! vtable->initialized)
4532                                         return FALSE;
4533                                 mono_runtime_class_init (vtable);
4534                         }
4535                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4536                         if (!method->klass->runtime_info)
4537                                 /* No vtable created yet */
4538                                 return FALSE;
4539                         vtable = mono_class_vtable (cfg->domain, method->klass);
4540                         if (!vtable)
4541                                 return FALSE;
4542                         if (!vtable->initialized)
4543                                 return FALSE;
4544                 }
4545         } else {
4546                 /* 
4547                  * If we're compiling for shared code
4548                  * the cctor will need to be run at aot method load time, for example,
4549                  * or at the end of the compilation of the inlining method.
4550                  */
4551                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4552                         return FALSE;
4553         }
4554
4555         /*
4556          * CAS - do not inline methods with declarative security
4557          * Note: this has to be before any possible return TRUE;
4558          */
4559         if (mono_security_method_has_declsec (method))
4560                 return FALSE;
4561
4562 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4563         if (mono_arch_is_soft_float ()) {
4564                 /* FIXME: */
4565                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4566                         return FALSE;
4567                 for (i = 0; i < sig->param_count; ++i)
4568                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4569                                 return FALSE;
4570         }
4571 #endif
4572
4573         return TRUE;
4574 }
4575
4576 static gboolean
4577 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
4578 {
4579         if (vtable->initialized && !cfg->compile_aot)
4580                 return FALSE;
4581
4582         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
4583                 return FALSE;
4584
4585         if (!mono_class_needs_cctor_run (vtable->klass, method))
4586                 return FALSE;
4587
4588         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
4589                 /* The initialization is already done before the method is called */
4590                 return FALSE;
4591
4592         return TRUE;
4593 }
4594
4595 static MonoInst*
4596 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4597 {
4598         MonoInst *ins;
4599         guint32 size;
4600         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4601         int context_used;
4602
4603         if (mini_is_gsharedvt_klass (cfg, klass)) {
4604                 size = -1;
4605         } else {
4606                 mono_class_init (klass);
4607                 size = mono_class_array_element_size (klass);
4608         }
4609
4610         mult_reg = alloc_preg (cfg);
4611         array_reg = arr->dreg;
4612         index_reg = index->dreg;
4613
4614 #if SIZEOF_REGISTER == 8
4615         /* The array reg is 64 bits but the index reg is only 32 */
4616         if (COMPILE_LLVM (cfg)) {
4617                 /* Not needed */
4618                 index2_reg = index_reg;
4619         } else {
4620                 index2_reg = alloc_preg (cfg);
4621                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4622         }
4623 #else
4624         if (index->type == STACK_I8) {
4625                 index2_reg = alloc_preg (cfg);
4626                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4627         } else {
4628                 index2_reg = index_reg;
4629         }
4630 #endif
4631
4632         if (bcheck)
4633                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4634
4635 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4636         if (size == 1 || size == 2 || size == 4 || size == 8) {
4637                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4638
4639                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4640                 ins->klass = mono_class_get_element_class (klass);
4641                 ins->type = STACK_MP;
4642
4643                 return ins;
4644         }
4645 #endif          
4646
4647         add_reg = alloc_ireg_mp (cfg);
4648
4649         if (size == -1) {
4650                 MonoInst *rgctx_ins;
4651
4652                 /* gsharedvt */
4653                 g_assert (cfg->generic_sharing_context);
4654                 context_used = mini_class_check_context_used (cfg, klass);
4655                 g_assert (context_used);
4656                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4657                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4658         } else {
4659                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4660         }
4661         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4662         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4663         ins->klass = mono_class_get_element_class (klass);
4664         ins->type = STACK_MP;
4665         MONO_ADD_INS (cfg->cbb, ins);
4666
4667         return ins;
4668 }
4669
4670 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4671 static MonoInst*
4672 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4673 {
4674         int bounds_reg = alloc_preg (cfg);
4675         int add_reg = alloc_ireg_mp (cfg);
4676         int mult_reg = alloc_preg (cfg);
4677         int mult2_reg = alloc_preg (cfg);
4678         int low1_reg = alloc_preg (cfg);
4679         int low2_reg = alloc_preg (cfg);
4680         int high1_reg = alloc_preg (cfg);
4681         int high2_reg = alloc_preg (cfg);
4682         int realidx1_reg = alloc_preg (cfg);
4683         int realidx2_reg = alloc_preg (cfg);
4684         int sum_reg = alloc_preg (cfg);
4685         int index1, index2, tmpreg;
4686         MonoInst *ins;
4687         guint32 size;
4688
4689         mono_class_init (klass);
4690         size = mono_class_array_element_size (klass);
4691
4692         index1 = index_ins1->dreg;
4693         index2 = index_ins2->dreg;
4694
4695 #if SIZEOF_REGISTER == 8
4696         /* The array reg is 64 bits but the index reg is only 32 */
4697         if (COMPILE_LLVM (cfg)) {
4698                 /* Not needed */
4699         } else {
4700                 tmpreg = alloc_preg (cfg);
4701                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4702                 index1 = tmpreg;
4703                 tmpreg = alloc_preg (cfg);
4704                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4705                 index2 = tmpreg;
4706         }
4707 #else
4708         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4709         tmpreg = -1;
4710 #endif
4711
4712         /* range checking */
4713         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4714                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4715
4716         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4717                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4718         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4719         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4720                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4721         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4722         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4723
4724         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4725                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4726         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4727         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4728                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4729         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4730         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4731
4732         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4733         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4734         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4735         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4736         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4737
4738         ins->type = STACK_MP;
4739         ins->klass = klass;
4740         MONO_ADD_INS (cfg->cbb, ins);
4741
4742         return ins;
4743 }
4744 #endif
4745
4746 static MonoInst*
4747 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4748 {
4749         int rank;
4750         MonoInst *addr;
4751         MonoMethod *addr_method;
4752         int element_size;
4753
4754         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4755
4756         if (rank == 1)
4757                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4758
4759 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4760         /* emit_ldelema_2 depends on OP_LMUL */
4761         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4762                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4763         }
4764 #endif
4765
4766         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4767         addr_method = mono_marshal_get_array_address (rank, element_size);
4768         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4769
4770         return addr;
4771 }
4772
4773 static MonoBreakPolicy
4774 always_insert_breakpoint (MonoMethod *method)
4775 {
4776         return MONO_BREAK_POLICY_ALWAYS;
4777 }
4778
4779 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4780
4781 /**
4782  * mono_set_break_policy:
4783  * policy_callback: the new callback function
4784  *
4785  * Allow embedders to decide wherther to actually obey breakpoint instructions
4786  * (both break IL instructions and Debugger.Break () method calls), for example
4787  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4788  * untrusted or semi-trusted code.
4789  *
4790  * @policy_callback will be called every time a break point instruction needs to
4791  * be inserted with the method argument being the method that calls Debugger.Break()
4792  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4793  * if it wants the breakpoint to not be effective in the given method.
4794  * #MONO_BREAK_POLICY_ALWAYS is the default.
4795  */
4796 void
4797 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4798 {
4799         if (policy_callback)
4800                 break_policy_func = policy_callback;
4801         else
4802                 break_policy_func = always_insert_breakpoint;
4803 }
4804
4805 static gboolean
4806 should_insert_brekpoint (MonoMethod *method) {
4807         switch (break_policy_func (method)) {
4808         case MONO_BREAK_POLICY_ALWAYS:
4809                 return TRUE;
4810         case MONO_BREAK_POLICY_NEVER:
4811                 return FALSE;
4812         case MONO_BREAK_POLICY_ON_DBG:
4813                 return mono_debug_using_mono_debugger ();
4814         default:
4815                 g_warning ("Incorrect value returned from break policy callback");
4816                 return FALSE;
4817         }
4818 }
4819
4820 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4821 static MonoInst*
4822 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4823 {
4824         MonoInst *addr, *store, *load;
4825         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4826
4827         /* the bounds check is already done by the callers */
4828         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4829         if (is_set) {
4830                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4831                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4832                 if (mini_type_is_reference (cfg, fsig->params [2]))
4833                         emit_write_barrier (cfg, addr, load);
4834         } else {
4835                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4836                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4837         }
4838         return store;
4839 }
4840
4841
4842 static gboolean
4843 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4844 {
4845         return mini_type_is_reference (cfg, &klass->byval_arg);
4846 }
4847
4848 static MonoInst*
4849 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4850 {
4851         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4852                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
4853                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4854                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4855                 MonoInst *iargs [3];
4856
4857                 if (!helper->slot)
4858                         mono_class_setup_vtable (obj_array);
4859                 g_assert (helper->slot);
4860
4861                 if (sp [0]->type != STACK_OBJ)
4862                         return NULL;
4863                 if (sp [2]->type != STACK_OBJ)
4864                         return NULL;
4865
4866                 iargs [2] = sp [2];
4867                 iargs [1] = sp [1];
4868                 iargs [0] = sp [0];
4869
4870                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4871         } else {
4872                 MonoInst *ins;
4873
4874                 if (mini_is_gsharedvt_klass (cfg, klass)) {
4875                         MonoInst *addr;
4876
4877                         // FIXME-VT: OP_ICONST optimization
4878                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4879                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4880                         ins->opcode = OP_STOREV_MEMBASE;
4881                 } else if (sp [1]->opcode == OP_ICONST) {
4882                         int array_reg = sp [0]->dreg;
4883                         int index_reg = sp [1]->dreg;
4884                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
4885
4886                         if (safety_checks)
4887                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4888                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4889                 } else {
4890                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4891                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4892                         if (generic_class_is_reference_type (cfg, klass))
4893                                 emit_write_barrier (cfg, addr, sp [2]);
4894                 }
4895                 return ins;
4896         }
4897 }
4898
4899 static MonoInst*
4900 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4901 {
4902         MonoClass *eklass;
4903         
4904         if (is_set)
4905                 eklass = mono_class_from_mono_type (fsig->params [2]);
4906         else
4907                 eklass = mono_class_from_mono_type (fsig->ret);
4908
4909
4910         if (is_set) {
4911                 return emit_array_store (cfg, eklass, args, FALSE);
4912         } else {
4913                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4914                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4915                 return ins;
4916         }
4917 }
4918
4919 static MonoInst*
4920 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4921 {
4922         MonoInst *ins = NULL;
4923 #ifdef MONO_ARCH_SIMD_INTRINSICS
4924         if (cfg->opt & MONO_OPT_SIMD) {
4925                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4926                 if (ins)
4927                         return ins;
4928         }
4929 #endif
4930
4931         return ins;
4932 }
4933
4934 static MonoInst*
4935 emit_memory_barrier (MonoCompile *cfg, int kind)
4936 {
4937         MonoInst *ins = NULL;
4938         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4939         MONO_ADD_INS (cfg->cbb, ins);
4940         ins->backend.memory_barrier_kind = kind;
4941
4942         return ins;
4943 }
4944
4945 static MonoInst*
4946 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4947 {
4948         MonoInst *ins = NULL;
4949         int opcode = 0;
4950
4951         /* The LLVM backend supports these intrinsics */
4952         if (cmethod->klass == mono_defaults.math_class) {
4953                 if (strcmp (cmethod->name, "Sin") == 0) {
4954                         opcode = OP_SIN;
4955                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4956                         opcode = OP_COS;
4957                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4958                         opcode = OP_SQRT;
4959                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4960                         opcode = OP_ABS;
4961                 }
4962
4963                 if (opcode) {
4964                         MONO_INST_NEW (cfg, ins, opcode);
4965                         ins->type = STACK_R8;
4966                         ins->dreg = mono_alloc_freg (cfg);
4967                         ins->sreg1 = args [0]->dreg;
4968                         MONO_ADD_INS (cfg->cbb, ins);
4969                 }
4970
4971                 opcode = 0;
4972                 if (cfg->opt & MONO_OPT_CMOV) {
4973                         if (strcmp (cmethod->name, "Min") == 0) {
4974                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4975                                         opcode = OP_IMIN;
4976                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4977                                         opcode = OP_IMIN_UN;
4978                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4979                                         opcode = OP_LMIN;
4980                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4981                                         opcode = OP_LMIN_UN;
4982                         } else if (strcmp (cmethod->name, "Max") == 0) {
4983                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4984                                         opcode = OP_IMAX;
4985                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4986                                         opcode = OP_IMAX_UN;
4987                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4988                                         opcode = OP_LMAX;
4989                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4990                                         opcode = OP_LMAX_UN;
4991                         }
4992                 }
4993
4994                 if (opcode) {
4995                         MONO_INST_NEW (cfg, ins, opcode);
4996                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
4997                         ins->dreg = mono_alloc_ireg (cfg);
4998                         ins->sreg1 = args [0]->dreg;
4999                         ins->sreg2 = args [1]->dreg;
5000                         MONO_ADD_INS (cfg->cbb, ins);
5001                 }
5002         }
5003
5004         return ins;
5005 }
5006
5007 static MonoInst*
5008 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5009 {
5010         if (cmethod->klass == mono_defaults.array_class) {
5011                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5012                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5013                 if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5014                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5015         }
5016
5017         return NULL;
5018 }
5019
5020 static MonoInst*
5021 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5022 {
5023         MonoInst *ins = NULL;
5024         
5025         static MonoClass *runtime_helpers_class = NULL;
5026         if (! runtime_helpers_class)
5027                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5028                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5029
5030         if (cmethod->klass == mono_defaults.string_class) {
5031                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5032                         int dreg = alloc_ireg (cfg);
5033                         int index_reg = alloc_preg (cfg);
5034                         int mult_reg = alloc_preg (cfg);
5035                         int add_reg = alloc_preg (cfg);
5036
5037 #if SIZEOF_REGISTER == 8
5038                         /* The array reg is 64 bits but the index reg is only 32 */
5039                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5040 #else
5041                         index_reg = args [1]->dreg;
5042 #endif  
5043                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5044
5045 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5046                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
5047                         add_reg = ins->dreg;
5048                         /* Avoid a warning */
5049                         mult_reg = 0;
5050                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5051                                                                    add_reg, 0);
5052 #else
5053                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5054                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5055                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5056                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5057 #endif
5058                         type_from_op (ins, NULL, NULL);
5059                         return ins;
5060                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5061                         int dreg = alloc_ireg (cfg);
5062                         /* Decompose later to allow more optimizations */
5063                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5064                         ins->type = STACK_I4;
5065                         ins->flags |= MONO_INST_FAULT;
5066                         cfg->cbb->has_array_access = TRUE;
5067                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5068
5069                         return ins;
5070                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5071                         int mult_reg = alloc_preg (cfg);
5072                         int add_reg = alloc_preg (cfg);
5073
5074                         /* The corlib functions check for oob already. */
5075                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5076                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5077                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5078                         return cfg->cbb->last_ins;
5079                 } else 
5080                         return NULL;
5081         } else if (cmethod->klass == mono_defaults.object_class) {
5082
5083                 if (strcmp (cmethod->name, "GetType") == 0) {
5084                         int dreg = alloc_ireg_ref (cfg);
5085                         int vt_reg = alloc_preg (cfg);
5086                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5087                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5088                         type_from_op (ins, NULL, NULL);
5089
5090                         return ins;
5091 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5092                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5093                         int dreg = alloc_ireg (cfg);
5094                         int t1 = alloc_ireg (cfg);
5095         
5096                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5097                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5098                         ins->type = STACK_I4;
5099
5100                         return ins;
5101 #endif
5102                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5103                         MONO_INST_NEW (cfg, ins, OP_NOP);
5104                         MONO_ADD_INS (cfg->cbb, ins);
5105                         return ins;
5106                 } else
5107                         return NULL;
5108         } else if (cmethod->klass == mono_defaults.array_class) {
5109                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5110                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5111
5112 #ifndef MONO_BIG_ARRAYS
5113                 /*
5114                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5115                  * Array methods.
5116                  */
5117                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5118                         int dreg = alloc_ireg (cfg);
5119                         int bounds_reg = alloc_ireg_mp (cfg);
5120                         MonoBasicBlock *end_bb, *szarray_bb;
5121                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5122
5123                         NEW_BBLOCK (cfg, end_bb);
5124                         NEW_BBLOCK (cfg, szarray_bb);
5125
5126                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5127                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5128                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5129                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5130                         /* Non-szarray case */
5131                         if (get_length)
5132                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5133                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5134                         else
5135                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5136                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5137                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5138                         MONO_START_BB (cfg, szarray_bb);
5139                         /* Szarray case */
5140                         if (get_length)
5141                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5142                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5143                         else
5144                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5145                         MONO_START_BB (cfg, end_bb);
5146
5147                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5148                         ins->type = STACK_I4;
5149                         
5150                         return ins;
5151                 }
5152 #endif
5153
5154                 if (cmethod->name [0] != 'g')
5155                         return NULL;
5156
5157                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5158                         int dreg = alloc_ireg (cfg);
5159                         int vtable_reg = alloc_preg (cfg);
5160                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5161                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5162                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5163                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5164                         type_from_op (ins, NULL, NULL);
5165
5166                         return ins;
5167                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5168                         int dreg = alloc_ireg (cfg);
5169
5170                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5171                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5172                         type_from_op (ins, NULL, NULL);
5173
5174                         return ins;
5175                 } else
5176                         return NULL;
5177         } else if (cmethod->klass == runtime_helpers_class) {
5178
5179                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5180                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5181                         return ins;
5182                 } else
5183                         return NULL;
5184         } else if (cmethod->klass == mono_defaults.thread_class) {
5185                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5186                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5187                         MONO_ADD_INS (cfg->cbb, ins);
5188                         return ins;
5189                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5190                         return emit_memory_barrier (cfg, FullBarrier);
5191                 }
5192         } else if (cmethod->klass == mono_defaults.monitor_class) {
5193
5194                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5195 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5196                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5197                         MonoMethod *fast_method = NULL;
5198
5199                         /* Avoid infinite recursion */
5200                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5201                                 return NULL;
5202                                 
5203                         fast_method = mono_monitor_get_fast_path (cmethod);
5204                         if (!fast_method)
5205                                 return NULL;
5206
5207                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5208                 }
5209 #endif
5210
5211 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5212                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5213                         MonoCallInst *call;
5214
5215                         if (COMPILE_LLVM (cfg)) {
5216                                 /* 
5217                                  * Pass the argument normally, the LLVM backend will handle the
5218                                  * calling convention problems.
5219                                  */
5220                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5221                         } else {
5222                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5223                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5224                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5225                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5226                         }
5227
5228                         return (MonoInst*)call;
5229                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5230                         MonoCallInst *call;
5231
5232                         if (COMPILE_LLVM (cfg)) {
5233                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5234                         } else {
5235                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5236                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5237                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5238                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5239                         }
5240
5241                         return (MonoInst*)call;
5242                 }
5243 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5244                 {
5245                 MonoMethod *fast_method = NULL;
5246
5247                 /* Avoid infinite recursion */
5248                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5249                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5250                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5251                         return NULL;
5252
5253                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5254                                 strcmp (cmethod->name, "Exit") == 0)
5255                         fast_method = mono_monitor_get_fast_path (cmethod);
5256                 if (!fast_method)
5257                         return NULL;
5258
5259                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5260                 }
5261 #endif
5262         } else if (cmethod->klass->image == mono_defaults.corlib &&
5263                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5264                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5265                 ins = NULL;
5266
5267 #if SIZEOF_REGISTER == 8
5268                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5269                         /* 64 bit reads are already atomic */
5270                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5271                         ins->dreg = mono_alloc_preg (cfg);
5272                         ins->inst_basereg = args [0]->dreg;
5273                         ins->inst_offset = 0;
5274                         MONO_ADD_INS (cfg->cbb, ins);
5275                 }
5276 #endif
5277
5278 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5279                 if (strcmp (cmethod->name, "Increment") == 0) {
5280                         MonoInst *ins_iconst;
5281                         guint32 opcode = 0;
5282
5283                         if (fsig->params [0]->type == MONO_TYPE_I4)
5284                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5285 #if SIZEOF_REGISTER == 8
5286                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5287                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5288 #endif
5289                         if (opcode) {
5290                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5291                                 ins_iconst->inst_c0 = 1;
5292                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5293                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5294
5295                                 MONO_INST_NEW (cfg, ins, opcode);
5296                                 ins->dreg = mono_alloc_ireg (cfg);
5297                                 ins->inst_basereg = args [0]->dreg;
5298                                 ins->inst_offset = 0;
5299                                 ins->sreg2 = ins_iconst->dreg;
5300                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5301                                 MONO_ADD_INS (cfg->cbb, ins);
5302                         }
5303                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5304                         MonoInst *ins_iconst;
5305                         guint32 opcode = 0;
5306
5307                         if (fsig->params [0]->type == MONO_TYPE_I4)
5308                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5309 #if SIZEOF_REGISTER == 8
5310                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5311                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5312 #endif
5313                         if (opcode) {
5314                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5315                                 ins_iconst->inst_c0 = -1;
5316                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5317                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5318
5319                                 MONO_INST_NEW (cfg, ins, opcode);
5320                                 ins->dreg = mono_alloc_ireg (cfg);
5321                                 ins->inst_basereg = args [0]->dreg;
5322                                 ins->inst_offset = 0;
5323                                 ins->sreg2 = ins_iconst->dreg;
5324                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5325                                 MONO_ADD_INS (cfg->cbb, ins);
5326                         }
5327                 } else if (strcmp (cmethod->name, "Add") == 0) {
5328                         guint32 opcode = 0;
5329
5330                         if (fsig->params [0]->type == MONO_TYPE_I4)
5331                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5332 #if SIZEOF_REGISTER == 8
5333                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5334                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5335 #endif
5336
5337                         if (opcode) {
5338                                 MONO_INST_NEW (cfg, ins, opcode);
5339                                 ins->dreg = mono_alloc_ireg (cfg);
5340                                 ins->inst_basereg = args [0]->dreg;
5341                                 ins->inst_offset = 0;
5342                                 ins->sreg2 = args [1]->dreg;
5343                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5344                                 MONO_ADD_INS (cfg->cbb, ins);
5345                         }
5346                 }
5347 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5348
5349 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5350                 if (strcmp (cmethod->name, "Exchange") == 0) {
5351                         guint32 opcode;
5352                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5353
5354                         if (fsig->params [0]->type == MONO_TYPE_I4)
5355                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5356 #if SIZEOF_REGISTER == 8
5357                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5358                                         (fsig->params [0]->type == MONO_TYPE_I))
5359                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5360 #else
5361                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
5362                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5363 #endif
5364                         else
5365                                 return NULL;
5366
5367                         MONO_INST_NEW (cfg, ins, opcode);
5368                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5369                         ins->inst_basereg = args [0]->dreg;
5370                         ins->inst_offset = 0;
5371                         ins->sreg2 = args [1]->dreg;
5372                         MONO_ADD_INS (cfg->cbb, ins);
5373
5374                         switch (fsig->params [0]->type) {
5375                         case MONO_TYPE_I4:
5376                                 ins->type = STACK_I4;
5377                                 break;
5378                         case MONO_TYPE_I8:
5379                         case MONO_TYPE_I:
5380                                 ins->type = STACK_I8;
5381                                 break;
5382                         case MONO_TYPE_OBJECT:
5383                                 ins->type = STACK_OBJ;
5384                                 break;
5385                         default:
5386                                 g_assert_not_reached ();
5387                         }
5388
5389                         if (cfg->gen_write_barriers && is_ref)
5390                                 emit_write_barrier (cfg, args [0], args [1]);
5391                 }
5392 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5393  
5394 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5395                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5396                         int size = 0;
5397                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5398                         if (fsig->params [1]->type == MONO_TYPE_I4)
5399                                 size = 4;
5400                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5401                                 size = sizeof (gpointer);
5402                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5403                                 size = 8;
5404                         if (size == 4) {
5405                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5406                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5407                                 ins->sreg1 = args [0]->dreg;
5408                                 ins->sreg2 = args [1]->dreg;
5409                                 ins->sreg3 = args [2]->dreg;
5410                                 ins->type = STACK_I4;
5411                                 MONO_ADD_INS (cfg->cbb, ins);
5412                         } else if (size == 8) {
5413                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5414                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5415                                 ins->sreg1 = args [0]->dreg;
5416                                 ins->sreg2 = args [1]->dreg;
5417                                 ins->sreg3 = args [2]->dreg;
5418                                 ins->type = STACK_I8;
5419                                 MONO_ADD_INS (cfg->cbb, ins);
5420                         } else {
5421                                 /* g_assert_not_reached (); */
5422                         }
5423                         if (cfg->gen_write_barriers && is_ref)
5424                                 emit_write_barrier (cfg, args [0], args [1]);
5425                 }
5426 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5427
5428                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5429                         ins = emit_memory_barrier (cfg, FullBarrier);
5430
5431                 if (ins)
5432                         return ins;
5433         } else if (cmethod->klass->image == mono_defaults.corlib) {
5434                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5435                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5436                         if (should_insert_brekpoint (cfg->method)) {
5437                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5438                         } else {
5439                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5440                                 MONO_ADD_INS (cfg->cbb, ins);
5441                         }
5442                         return ins;
5443                 }
5444                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5445                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5446 #ifdef TARGET_WIN32
5447                         EMIT_NEW_ICONST (cfg, ins, 1);
5448 #else
5449                         EMIT_NEW_ICONST (cfg, ins, 0);
5450 #endif
5451                         return ins;
5452                 }
5453         } else if (cmethod->klass == mono_defaults.math_class) {
5454                 /* 
5455                  * There is general branches code for Min/Max, but it does not work for 
5456                  * all inputs:
5457                  * http://everything2.com/?node_id=1051618
5458                  */
5459         }
5460
5461 #ifdef MONO_ARCH_SIMD_INTRINSICS
5462         if (cfg->opt & MONO_OPT_SIMD) {
5463                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5464                 if (ins)
5465                         return ins;
5466         }
5467 #endif
5468
5469         if (COMPILE_LLVM (cfg)) {
5470                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5471                 if (ins)
5472                         return ins;
5473         }
5474
5475         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5476 }
5477
5478 /*
5479  * This entry point could be used later for arbitrary method
5480  * redirection.
5481  */
5482 inline static MonoInst*
5483 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5484                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5485 {
5486         if (method->klass == mono_defaults.string_class) {
5487                 /* managed string allocation support */
5488                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5489                         MonoInst *iargs [2];
5490                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5491                         MonoMethod *managed_alloc = NULL;
5492
5493                         g_assert (vtable); /*Should not fail since it System.String*/
5494 #ifndef MONO_CROSS_COMPILE
5495                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5496 #endif
5497                         if (!managed_alloc)
5498                                 return NULL;
5499                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5500                         iargs [1] = args [0];
5501                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5502                 }
5503         }
5504         return NULL;
5505 }
5506
5507 static void
5508 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5509 {
5510         MonoInst *store, *temp;
5511         int i;
5512
5513         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5514                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5515
5516                 /*
5517                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5518                  * would be different than the MonoInst's used to represent arguments, and
5519                  * the ldelema implementation can't deal with that.
5520                  * Solution: When ldelema is used on an inline argument, create a var for 
5521                  * it, emit ldelema on that var, and emit the saving code below in
5522                  * inline_method () if needed.
5523                  */
5524                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5525                 cfg->args [i] = temp;
5526                 /* This uses cfg->args [i] which is set by the preceeding line */
5527                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5528                 store->cil_code = sp [0]->cil_code;
5529                 sp++;
5530         }
5531 }
5532
5533 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5534 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5535
5536 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5537 static gboolean
5538 check_inline_called_method_name_limit (MonoMethod *called_method)
5539 {
5540         int strncmp_result;
5541         static char *limit = NULL;
5542         
5543         if (limit == NULL) {
5544                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5545
5546                 if (limit_string != NULL)
5547                         limit = limit_string;
5548                 else
5549                         limit = (char *) "";
5550         }
5551
5552         if (limit [0] != '\0') {
5553                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5554
5555                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5556                 g_free (called_method_name);
5557         
5558                 //return (strncmp_result <= 0);
5559                 return (strncmp_result == 0);
5560         } else {
5561                 return TRUE;
5562         }
5563 }
5564 #endif
5565
5566 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5567 static gboolean
5568 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5569 {
5570         int strncmp_result;
5571         static char *limit = NULL;
5572         
5573         if (limit == NULL) {
5574                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5575                 if (limit_string != NULL) {
5576                         limit = limit_string;
5577                 } else {
5578                         limit = (char *) "";
5579                 }
5580         }
5581
5582         if (limit [0] != '\0') {
5583                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5584
5585                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5586                 g_free (caller_method_name);
5587         
5588                 //return (strncmp_result <= 0);
5589                 return (strncmp_result == 0);
5590         } else {
5591                 return TRUE;
5592         }
5593 }
5594 #endif
5595
5596 static void
5597 emit_init_rvar (MonoCompile *cfg, MonoInst *rvar, MonoType *rtype)
5598 {
5599         static double r8_0 = 0.0;
5600         MonoInst *ins;
5601
5602         switch (rvar->type) {
5603         case STACK_I4:
5604                 MONO_EMIT_NEW_ICONST (cfg, rvar->dreg, 0);
5605                 break;
5606         case STACK_I8:
5607                 MONO_EMIT_NEW_I8CONST (cfg, rvar->dreg, 0);
5608                 break;
5609         case STACK_PTR:
5610         case STACK_MP:
5611         case STACK_OBJ:
5612                 MONO_EMIT_NEW_PCONST (cfg, rvar->dreg, 0);
5613                 break;
5614         case STACK_R8:
5615                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5616                 ins->type = STACK_R8;
5617                 ins->inst_p0 = (void*)&r8_0;
5618                 ins->dreg = rvar->dreg;
5619                 MONO_ADD_INS (cfg->cbb, ins);
5620                 break;
5621         case STACK_VTYPE:
5622                 MONO_EMIT_NEW_VZERO (cfg, rvar->dreg, mono_class_from_mono_type (rtype));
5623                 break;
5624         default:
5625                 g_assert_not_reached ();
5626         }
5627 }
5628
5629 static int
5630 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5631                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5632 {
5633         MonoInst *ins, *rvar = NULL;
5634         MonoMethodHeader *cheader;
5635         MonoBasicBlock *ebblock, *sbblock;
5636         int i, costs;
5637         MonoMethod *prev_inlined_method;
5638         MonoInst **prev_locals, **prev_args;
5639         MonoType **prev_arg_types;
5640         guint prev_real_offset;
5641         GHashTable *prev_cbb_hash;
5642         MonoBasicBlock **prev_cil_offset_to_bb;
5643         MonoBasicBlock *prev_cbb;
5644         unsigned char* prev_cil_start;
5645         guint32 prev_cil_offset_to_bb_len;
5646         MonoMethod *prev_current_method;
5647         MonoGenericContext *prev_generic_context;
5648         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5649
5650         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5651
5652 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5653         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5654                 return 0;
5655 #endif
5656 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5657         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5658                 return 0;
5659 #endif
5660
5661         if (cfg->verbose_level > 2)
5662                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5663
5664         if (!cmethod->inline_info) {
5665                 cfg->stat_inlineable_methods++;
5666                 cmethod->inline_info = 1;
5667         }
5668
5669         /* allocate local variables */
5670         cheader = mono_method_get_header (cmethod);
5671
5672         if (cheader == NULL || mono_loader_get_last_error ()) {
5673                 MonoLoaderError *error = mono_loader_get_last_error ();
5674
5675                 if (cheader)
5676                         mono_metadata_free_mh (cheader);
5677                 if (inline_always && error)
5678                         mono_cfg_set_exception (cfg, error->exception_type);
5679
5680                 mono_loader_clear_error ();
5681                 return 0;
5682         }
5683
5684         /*Must verify before creating locals as it can cause the JIT to assert.*/
5685         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5686                 mono_metadata_free_mh (cheader);
5687                 return 0;
5688         }
5689
5690         /* allocate space to store the return value */
5691         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5692                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5693         }
5694
5695         prev_locals = cfg->locals;
5696         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5697         for (i = 0; i < cheader->num_locals; ++i)
5698                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5699
5700         /* allocate start and end blocks */
5701         /* This is needed so if the inline is aborted, we can clean up */
5702         NEW_BBLOCK (cfg, sbblock);
5703         sbblock->real_offset = real_offset;
5704
5705         NEW_BBLOCK (cfg, ebblock);
5706         ebblock->block_num = cfg->num_bblocks++;
5707         ebblock->real_offset = real_offset;
5708
5709         prev_args = cfg->args;
5710         prev_arg_types = cfg->arg_types;
5711         prev_inlined_method = cfg->inlined_method;
5712         cfg->inlined_method = cmethod;
5713         cfg->ret_var_set = FALSE;
5714         cfg->inline_depth ++;
5715         prev_real_offset = cfg->real_offset;
5716         prev_cbb_hash = cfg->cbb_hash;
5717         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
5718         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
5719         prev_cil_start = cfg->cil_start;
5720         prev_cbb = cfg->cbb;
5721         prev_current_method = cfg->current_method;
5722         prev_generic_context = cfg->generic_context;
5723         prev_ret_var_set = cfg->ret_var_set;
5724
5725         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
5726                 virtual = TRUE;
5727
5728         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
5729
5730         ret_var_set = cfg->ret_var_set;
5731
5732         cfg->inlined_method = prev_inlined_method;
5733         cfg->real_offset = prev_real_offset;
5734         cfg->cbb_hash = prev_cbb_hash;
5735         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
5736         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
5737         cfg->cil_start = prev_cil_start;
5738         cfg->locals = prev_locals;
5739         cfg->args = prev_args;
5740         cfg->arg_types = prev_arg_types;
5741         cfg->current_method = prev_current_method;
5742         cfg->generic_context = prev_generic_context;
5743         cfg->ret_var_set = prev_ret_var_set;
5744         cfg->inline_depth --;
5745
5746         if ((costs >= 0 && costs < 60) || inline_always) {
5747                 if (cfg->verbose_level > 2)
5748                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5749                 
5750                 cfg->stat_inlined_methods++;
5751
5752                 /* always add some code to avoid block split failures */
5753                 MONO_INST_NEW (cfg, ins, OP_NOP);
5754                 MONO_ADD_INS (prev_cbb, ins);
5755
5756                 prev_cbb->next_bb = sbblock;
5757                 link_bblock (cfg, prev_cbb, sbblock);
5758
5759                 /* 
5760                  * Get rid of the begin and end bblocks if possible to aid local
5761                  * optimizations.
5762                  */
5763                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
5764
5765                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
5766                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
5767
5768                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
5769                         MonoBasicBlock *prev = ebblock->in_bb [0];
5770                         mono_merge_basic_blocks (cfg, prev, ebblock);
5771                         cfg->cbb = prev;
5772                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
5773                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
5774                                 cfg->cbb = prev_cbb;
5775                         }
5776                 } else {
5777                         /* 
5778                          * Its possible that the rvar is set in some prev bblock, but not in others.
5779                          * (#1835).
5780                          */
5781                         if (rvar) {
5782                                 MonoBasicBlock *bb;
5783
5784                                 for (i = 0; i < ebblock->in_count; ++i) {
5785                                         bb = ebblock->in_bb [i];
5786
5787                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
5788                                                 cfg->cbb = bb;
5789
5790                                                 emit_init_rvar (cfg, rvar, fsig->ret);
5791                                         }
5792                                 }
5793                         }
5794
5795                         cfg->cbb = ebblock;
5796                 }
5797
5798                 if (rvar) {
5799                         /*
5800                          * If the inlined method contains only a throw, then the ret var is not 
5801                          * set, so set it to a dummy value.
5802                          */
5803                         if (!ret_var_set)
5804                                 emit_init_rvar (cfg, rvar, fsig->ret);
5805
5806                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
5807                         *sp++ = ins;
5808                 }
5809                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5810                 return costs + 1;
5811         } else {
5812                 if (cfg->verbose_level > 2)
5813                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
5814                 cfg->exception_type = MONO_EXCEPTION_NONE;
5815                 mono_loader_clear_error ();
5816
5817                 /* This gets rid of the newly added bblocks */
5818                 cfg->cbb = prev_cbb;
5819         }
5820         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5821         return 0;
5822 }
5823
5824 /*
5825  * Some of these comments may well be out-of-date.
5826  * Design decisions: we do a single pass over the IL code (and we do bblock 
5827  * splitting/merging in the few cases when it's required: a back jump to an IL
5828  * address that was not already seen as bblock starting point).
5829  * Code is validated as we go (full verification is still better left to metadata/verify.c).
5830  * Complex operations are decomposed in simpler ones right away. We need to let the 
5831  * arch-specific code peek and poke inside this process somehow (except when the 
5832  * optimizations can take advantage of the full semantic info of coarse opcodes).
5833  * All the opcodes of the form opcode.s are 'normalized' to opcode.
5834  * MonoInst->opcode initially is the IL opcode or some simplification of that 
5835  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
5836  * opcode with value bigger than OP_LAST.
5837  * At this point the IR can be handed over to an interpreter, a dumb code generator
5838  * or to the optimizing code generator that will translate it to SSA form.
5839  *
5840  * Profiling directed optimizations.
5841  * We may compile by default with few or no optimizations and instrument the code
5842  * or the user may indicate what methods to optimize the most either in a config file
5843  * or through repeated runs where the compiler applies offline the optimizations to 
5844  * each method and then decides if it was worth it.
5845  */
5846
5847 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
5848 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
5849 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
5850 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
5851 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
5852 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
5853 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
5854 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
5855
5856 /* offset from br.s -> br like opcodes */
5857 #define BIG_BRANCH_OFFSET 13
5858
5859 static gboolean
5860 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
5861 {
5862         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
5863
5864         return b == NULL || b == bb;
5865 }
5866
5867 static int
5868 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
5869 {
5870         unsigned char *ip = start;
5871         unsigned char *target;
5872         int i;
5873         guint cli_addr;
5874         MonoBasicBlock *bblock;
5875         const MonoOpcode *opcode;
5876
5877         while (ip < end) {
5878                 cli_addr = ip - start;
5879                 i = mono_opcode_value ((const guint8 **)&ip, end);
5880                 if (i < 0)
5881                         UNVERIFIED;
5882                 opcode = &mono_opcodes [i];
5883                 switch (opcode->argument) {
5884                 case MonoInlineNone:
5885                         ip++; 
5886                         break;
5887                 case MonoInlineString:
5888                 case MonoInlineType:
5889                 case MonoInlineField:
5890                 case MonoInlineMethod:
5891                 case MonoInlineTok:
5892                 case MonoInlineSig:
5893                 case MonoShortInlineR:
5894                 case MonoInlineI:
5895                         ip += 5;
5896                         break;
5897                 case MonoInlineVar:
5898                         ip += 3;
5899                         break;
5900                 case MonoShortInlineVar:
5901                 case MonoShortInlineI:
5902                         ip += 2;
5903                         break;
5904                 case MonoShortInlineBrTarget:
5905                         target = start + cli_addr + 2 + (signed char)ip [1];
5906                         GET_BBLOCK (cfg, bblock, target);
5907                         ip += 2;
5908                         if (ip < end)
5909                                 GET_BBLOCK (cfg, bblock, ip);
5910                         break;
5911                 case MonoInlineBrTarget:
5912                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
5913                         GET_BBLOCK (cfg, bblock, target);
5914                         ip += 5;
5915                         if (ip < end)
5916                                 GET_BBLOCK (cfg, bblock, ip);
5917                         break;
5918                 case MonoInlineSwitch: {
5919                         guint32 n = read32 (ip + 1);
5920                         guint32 j;
5921                         ip += 5;
5922                         cli_addr += 5 + 4 * n;
5923                         target = start + cli_addr;
5924                         GET_BBLOCK (cfg, bblock, target);
5925                         
5926                         for (j = 0; j < n; ++j) {
5927                                 target = start + cli_addr + (gint32)read32 (ip);
5928                                 GET_BBLOCK (cfg, bblock, target);
5929                                 ip += 4;
5930                         }
5931                         break;
5932                 }
5933                 case MonoInlineR:
5934                 case MonoInlineI8:
5935                         ip += 9;
5936                         break;
5937                 default:
5938                         g_assert_not_reached ();
5939                 }
5940
5941                 if (i == CEE_THROW) {
5942                         unsigned char *bb_start = ip - 1;
5943                         
5944                         /* Find the start of the bblock containing the throw */
5945                         bblock = NULL;
5946                         while ((bb_start >= start) && !bblock) {
5947                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
5948                                 bb_start --;
5949                         }
5950                         if (bblock)
5951                                 bblock->out_of_line = 1;
5952                 }
5953         }
5954         return 0;
5955 unverified:
5956 exception_exit:
5957         *pos = ip;
5958         return 1;
5959 }
5960
5961 static inline MonoMethod *
5962 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5963 {
5964         MonoMethod *method;
5965
5966         if (m->wrapper_type != MONO_WRAPPER_NONE) {
5967                 method = mono_method_get_wrapper_data (m, token);
5968                 if (context)
5969                         method = mono_class_inflate_generic_method (method, context);
5970         } else {
5971                 method = mono_get_method_full (m->klass->image, token, klass, context);
5972         }
5973
5974         return method;
5975 }
5976
5977 static inline MonoMethod *
5978 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5979 {
5980         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
5981
5982         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
5983                 return NULL;
5984
5985         return method;
5986 }
5987
5988 static inline MonoClass*
5989 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
5990 {
5991         MonoClass *klass;
5992
5993         if (method->wrapper_type != MONO_WRAPPER_NONE) {
5994                 klass = mono_method_get_wrapper_data (method, token);
5995                 if (context)
5996                         klass = mono_class_inflate_generic_class (klass, context);
5997         } else {
5998                 klass = mono_class_get_full (method->klass->image, token, context);
5999         }
6000         if (klass)
6001                 mono_class_init (klass);
6002         return klass;
6003 }
6004
6005 static inline MonoMethodSignature*
6006 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6007 {
6008         MonoMethodSignature *fsig;
6009
6010         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6011                 MonoError error;
6012
6013                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6014                 if (context) {
6015                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6016                         // FIXME:
6017                         g_assert (mono_error_ok (&error));
6018                 }
6019         } else {
6020                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6021         }
6022         return fsig;
6023 }
6024
6025 /*
6026  * Returns TRUE if the JIT should abort inlining because "callee"
6027  * is influenced by security attributes.
6028  */
6029 static
6030 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6031 {
6032         guint32 result;
6033         
6034         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6035                 return TRUE;
6036         }
6037         
6038         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6039         if (result == MONO_JIT_SECURITY_OK)
6040                 return FALSE;
6041
6042         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6043                 /* Generate code to throw a SecurityException before the actual call/link */
6044                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6045                 MonoInst *args [2];
6046
6047                 NEW_ICONST (cfg, args [0], 4);
6048                 NEW_METHODCONST (cfg, args [1], caller);
6049                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6050         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6051                  /* don't hide previous results */
6052                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6053                 cfg->exception_data = result;
6054                 return TRUE;
6055         }
6056         
6057         return FALSE;
6058 }
6059
6060 static MonoMethod*
6061 throw_exception (void)
6062 {
6063         static MonoMethod *method = NULL;
6064
6065         if (!method) {
6066                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6067                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6068         }
6069         g_assert (method);
6070         return method;
6071 }
6072
6073 static void
6074 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6075 {
6076         MonoMethod *thrower = throw_exception ();
6077         MonoInst *args [1];
6078
6079         EMIT_NEW_PCONST (cfg, args [0], ex);
6080         mono_emit_method_call (cfg, thrower, args, NULL);
6081 }
6082
6083 /*
6084  * Return the original method is a wrapper is specified. We can only access 
6085  * the custom attributes from the original method.
6086  */
6087 static MonoMethod*
6088 get_original_method (MonoMethod *method)
6089 {
6090         if (method->wrapper_type == MONO_WRAPPER_NONE)
6091                 return method;
6092
6093         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6094         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6095                 return NULL;
6096
6097         /* in other cases we need to find the original method */
6098         return mono_marshal_method_from_wrapper (method);
6099 }
6100
6101 static void
6102 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6103                                           MonoBasicBlock *bblock, unsigned char *ip)
6104 {
6105         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6106         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6107         if (ex)
6108                 emit_throw_exception (cfg, ex);
6109 }
6110
6111 static void
6112 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6113                                          MonoBasicBlock *bblock, unsigned char *ip)
6114 {
6115         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6116         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6117         if (ex)
6118                 emit_throw_exception (cfg, ex);
6119 }
6120
6121 /*
6122  * Check that the IL instructions at ip are the array initialization
6123  * sequence and return the pointer to the data and the size.
6124  */
6125 static const char*
6126 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6127 {
6128         /*
6129          * newarr[System.Int32]
6130          * dup
6131          * ldtoken field valuetype ...
6132          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6133          */
6134         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6135                 guint32 token = read32 (ip + 7);
6136                 guint32 field_token = read32 (ip + 2);
6137                 guint32 field_index = field_token & 0xffffff;
6138                 guint32 rva;
6139                 const char *data_ptr;
6140                 int size = 0;
6141                 MonoMethod *cmethod;
6142                 MonoClass *dummy_class;
6143                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6144                 int dummy_align;
6145
6146                 if (!field)
6147                         return NULL;
6148
6149                 *out_field_token = field_token;
6150
6151                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6152                 if (!cmethod)
6153                         return NULL;
6154                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6155                         return NULL;
6156                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6157                 case MONO_TYPE_BOOLEAN:
6158                 case MONO_TYPE_I1:
6159                 case MONO_TYPE_U1:
6160                         size = 1; break;
6161                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6162 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6163                 case MONO_TYPE_CHAR:
6164                 case MONO_TYPE_I2:
6165                 case MONO_TYPE_U2:
6166                         size = 2; break;
6167                 case MONO_TYPE_I4:
6168                 case MONO_TYPE_U4:
6169                 case MONO_TYPE_R4:
6170                         size = 4; break;
6171                 case MONO_TYPE_R8:
6172 #ifdef ARM_FPU_FPA
6173                         return NULL; /* stupid ARM FP swapped format */
6174 #endif
6175                 case MONO_TYPE_I8:
6176                 case MONO_TYPE_U8:
6177                         size = 8; break;
6178 #endif
6179                 default:
6180                         return NULL;
6181                 }
6182                 size *= len;
6183                 if (size > mono_type_size (field->type, &dummy_align))
6184                     return NULL;
6185                 *out_size = size;
6186                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6187                 if (!method->klass->image->dynamic) {
6188                         field_index = read32 (ip + 2) & 0xffffff;
6189                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6190                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6191                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6192                         /* for aot code we do the lookup on load */
6193                         if (aot && data_ptr)
6194                                 return GUINT_TO_POINTER (rva);
6195                 } else {
6196                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6197                         g_assert (!aot);
6198                         data_ptr = mono_field_get_data (field);
6199                 }
6200                 return data_ptr;
6201         }
6202         return NULL;
6203 }
6204
6205 static void
6206 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6207 {
6208         char *method_fname = mono_method_full_name (method, TRUE);
6209         char *method_code;
6210         MonoMethodHeader *header = mono_method_get_header (method);
6211
6212         if (header->code_size == 0)
6213                 method_code = g_strdup ("method body is empty.");
6214         else
6215                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6216         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6217         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6218         g_free (method_fname);
6219         g_free (method_code);
6220         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6221 }
6222
6223 static void
6224 set_exception_object (MonoCompile *cfg, MonoException *exception)
6225 {
6226         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6227         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6228         cfg->exception_ptr = exception;
6229 }
6230
6231 static void
6232 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6233 {
6234         MonoInst *ins;
6235         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6236         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6237                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6238                 /* Optimize reg-reg moves away */
6239                 /* 
6240                  * Can't optimize other opcodes, since sp[0] might point to
6241                  * the last ins of a decomposed opcode.
6242                  */
6243                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6244         } else {
6245                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6246         }
6247 }
6248
6249 /*
6250  * ldloca inhibits many optimizations so try to get rid of it in common
6251  * cases.
6252  */
6253 static inline unsigned char *
6254 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6255 {
6256         int local, token;
6257         MonoClass *klass;
6258
6259         if (size == 1) {
6260                 local = ip [1];
6261                 ip += 2;
6262         } else {
6263                 local = read16 (ip + 2);
6264                 ip += 4;
6265         }
6266         
6267         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6268                 gboolean skip = FALSE;
6269
6270                 /* From the INITOBJ case */
6271                 token = read32 (ip + 2);
6272                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6273                 CHECK_TYPELOAD (klass);
6274                 if (mini_type_is_reference (cfg, &klass->byval_arg)) {
6275                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
6276                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
6277                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [local]->dreg, klass);
6278                 } else {
6279                         skip = TRUE;
6280                 }
6281                         
6282                 if (!skip)
6283                         return ip + 6;
6284         }
6285 load_error:
6286         return NULL;
6287 }
6288
6289 static gboolean
6290 is_exception_class (MonoClass *class)
6291 {
6292         while (class) {
6293                 if (class == mono_defaults.exception_class)
6294                         return TRUE;
6295                 class = class->parent;
6296         }
6297         return FALSE;
6298 }
6299
6300 /*
6301  * is_jit_optimizer_disabled:
6302  *
6303  *   Determine whenever M's assembly has a DebuggableAttribute with the
6304  * IsJITOptimizerDisabled flag set.
6305  */
6306 static gboolean
6307 is_jit_optimizer_disabled (MonoMethod *m)
6308 {
6309         MonoAssembly *ass = m->klass->image->assembly;
6310         MonoCustomAttrInfo* attrs;
6311         static MonoClass *klass;
6312         int i;
6313         gboolean val = FALSE;
6314
6315         g_assert (ass);
6316         if (ass->jit_optimizer_disabled_inited)
6317                 return ass->jit_optimizer_disabled;
6318
6319         if (!klass)
6320                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6321         if (!klass) {
6322                 /* Linked away */
6323                 ass->jit_optimizer_disabled = FALSE;
6324                 mono_memory_barrier ();
6325                 ass->jit_optimizer_disabled_inited = TRUE;
6326                 return FALSE;
6327         }
6328
6329         attrs = mono_custom_attrs_from_assembly (ass);
6330         if (attrs) {
6331                 for (i = 0; i < attrs->num_attrs; ++i) {
6332                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6333                         const gchar *p;
6334                         int len;
6335                         MonoMethodSignature *sig;
6336
6337                         if (!attr->ctor || attr->ctor->klass != klass)
6338                                 continue;
6339                         /* Decode the attribute. See reflection.c */
6340                         len = attr->data_size;
6341                         p = (const char*)attr->data;
6342                         g_assert (read16 (p) == 0x0001);
6343                         p += 2;
6344
6345                         // FIXME: Support named parameters
6346                         sig = mono_method_signature (attr->ctor);
6347                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6348                                 continue;
6349                         /* Two boolean arguments */
6350                         p ++;
6351                         val = *p;
6352                 }
6353                 mono_custom_attrs_free (attrs);
6354         }
6355
6356         ass->jit_optimizer_disabled = val;
6357         mono_memory_barrier ();
6358         ass->jit_optimizer_disabled_inited = TRUE;
6359
6360         return val;
6361 }
6362
6363 static gboolean
6364 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig)
6365 {
6366         gboolean supported_tail_call;
6367         int i;
6368
6369 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6370         supported_tail_call = MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
6371 #else
6372         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6373 #endif
6374
6375         for (i = 0; i < fsig->param_count; ++i) {
6376                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6377                         /* These can point to the current method's stack */
6378                         supported_tail_call = FALSE;
6379         }
6380         if (fsig->hasthis && cmethod->klass->valuetype)
6381                 /* this might point to the current method's stack */
6382                 supported_tail_call = FALSE;
6383         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6384                 supported_tail_call = FALSE;
6385         if (cfg->method->save_lmf)
6386                 supported_tail_call = FALSE;
6387         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6388                 supported_tail_call = FALSE;
6389
6390         /* Debugging support */
6391 #if 0
6392         if (supported_tail_call) {
6393                 if (!mono_debug_count ())
6394                         supported_tail_call = FALSE;
6395         }
6396 #endif
6397
6398         return supported_tail_call;
6399 }
6400
6401 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6402  * it to the thread local value based on the tls_offset field. Every other kind of access to
6403  * the field causes an assert.
6404  */
6405 static gboolean
6406 is_magic_tls_access (MonoClassField *field)
6407 {
6408         if (strcmp (field->name, "tlsdata"))
6409                 return FALSE;
6410         if (strcmp (field->parent->name, "ThreadLocal`1"))
6411                 return FALSE;
6412         return field->parent->image == mono_defaults.corlib;
6413 }
6414
6415 /* emits the code needed to access a managed tls var (like ThreadStatic)
6416  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6417  * pointer for the current thread.
6418  * Returns the MonoInst* representing the address of the tls var.
6419  */
6420 static MonoInst*
6421 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6422 {
6423         MonoInst *addr;
6424         int static_data_reg, array_reg, dreg;
6425         int offset2_reg, idx_reg;
6426         // inlined access to the tls data
6427         // idx = (offset >> 24) - 1;
6428         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6429         static_data_reg = alloc_ireg (cfg);
6430         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6431         idx_reg = alloc_ireg (cfg);
6432         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6433         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6434         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6435         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6436         array_reg = alloc_ireg (cfg);
6437         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6438         offset2_reg = alloc_ireg (cfg);
6439         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6440         dreg = alloc_ireg (cfg);
6441         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6442         return addr;
6443 }
6444
6445 /*
6446  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6447  * this address is cached per-method in cached_tls_addr.
6448  */
6449 static MonoInst*
6450 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6451 {
6452         MonoInst *load, *addr, *temp, *store, *thread_ins;
6453         MonoClassField *offset_field;
6454
6455         if (*cached_tls_addr) {
6456                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6457                 return addr;
6458         }
6459         thread_ins = mono_get_thread_intrinsic (cfg);
6460         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6461
6462         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6463         if (thread_ins) {
6464                 MONO_ADD_INS (cfg->cbb, thread_ins);
6465         } else {
6466                 MonoMethod *thread_method;
6467                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6468                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6469         }
6470         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6471         addr->klass = mono_class_from_mono_type (tls_field->type);
6472         addr->type = STACK_MP;
6473         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6474         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6475
6476         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6477         return addr;
6478 }
6479
6480 /*
6481  * mono_method_to_ir:
6482  *
6483  *   Translate the .net IL into linear IR.
6484  */
6485 int
6486 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6487                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6488                    guint inline_offset, gboolean is_virtual_call)
6489 {
6490         MonoError error;
6491         MonoInst *ins, **sp, **stack_start;
6492         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6493         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6494         MonoMethod *cmethod, *method_definition;
6495         MonoInst **arg_array;
6496         MonoMethodHeader *header;
6497         MonoImage *image;
6498         guint32 token, ins_flag;
6499         MonoClass *klass;
6500         MonoClass *constrained_call = NULL;
6501         unsigned char *ip, *end, *target, *err_pos;
6502         static double r8_0 = 0.0;
6503         MonoMethodSignature *sig;
6504         MonoGenericContext *generic_context = NULL;
6505         MonoGenericContainer *generic_container = NULL;
6506         MonoType **param_types;
6507         int i, n, start_new_bblock, dreg;
6508         int num_calls = 0, inline_costs = 0;
6509         int breakpoint_id = 0;
6510         guint num_args;
6511         MonoBoolean security, pinvoke;
6512         MonoSecurityManager* secman = NULL;
6513         MonoDeclSecurityActions actions;
6514         GSList *class_inits = NULL;
6515         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6516         int context_used;
6517         gboolean init_locals, seq_points, skip_dead_blocks;
6518         gboolean disable_inline, sym_seq_points = FALSE;
6519         MonoInst *cached_tls_addr = NULL;
6520         MonoDebugMethodInfo *minfo;
6521         MonoBitSet *seq_point_locs = NULL;
6522         MonoBitSet *seq_point_set_locs = NULL;
6523
6524         disable_inline = is_jit_optimizer_disabled (method);
6525
6526         /* serialization and xdomain stuff may need access to private fields and methods */
6527         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6528         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6529         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6530         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6531         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6532         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6533
6534         dont_verify |= mono_security_smcs_hack_enabled ();
6535
6536         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6537         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6538         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6539         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6540         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6541
6542         image = method->klass->image;
6543         header = mono_method_get_header (method);
6544         if (!header) {
6545                 MonoLoaderError *error;
6546
6547                 if ((error = mono_loader_get_last_error ())) {
6548                         mono_cfg_set_exception (cfg, error->exception_type);
6549                 } else {
6550                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6551                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6552                 }
6553                 goto exception_exit;
6554         }
6555         generic_container = mono_method_get_generic_container (method);
6556         sig = mono_method_signature (method);
6557         num_args = sig->hasthis + sig->param_count;
6558         ip = (unsigned char*)header->code;
6559         cfg->cil_start = ip;
6560         end = ip + header->code_size;
6561         cfg->stat_cil_code_size += header->code_size;
6562         init_locals = header->init_locals;
6563
6564         seq_points = cfg->gen_seq_points && cfg->method == method;
6565 #ifdef PLATFORM_ANDROID
6566         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6567 #endif
6568
6569         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6570                 /* We could hit a seq point before attaching to the JIT (#8338) */
6571                 seq_points = FALSE;
6572         }
6573
6574         if (cfg->gen_seq_points && cfg->method == method) {
6575                 minfo = mono_debug_lookup_method (method);
6576                 if (minfo) {
6577                         int i, n_il_offsets;
6578                         int *il_offsets;
6579                         int *line_numbers;
6580
6581                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6582                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6583                         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);
6584                         sym_seq_points = TRUE;
6585                         for (i = 0; i < n_il_offsets; ++i) {
6586                                 if (il_offsets [i] < header->code_size)
6587                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6588                         }
6589                 }
6590         }
6591
6592         /* 
6593          * Methods without init_locals set could cause asserts in various passes
6594          * (#497220).
6595          */
6596         init_locals = TRUE;
6597
6598         method_definition = method;
6599         while (method_definition->is_inflated) {
6600                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6601                 method_definition = imethod->declaring;
6602         }
6603
6604         /* SkipVerification is not allowed if core-clr is enabled */
6605         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6606                 dont_verify = TRUE;
6607                 dont_verify_stloc = TRUE;
6608         }
6609
6610         if (mono_debug_using_mono_debugger ())
6611                 cfg->keep_cil_nops = TRUE;
6612
6613         if (sig->is_inflated)
6614                 generic_context = mono_method_get_context (method);
6615         else if (generic_container)
6616                 generic_context = &generic_container->context;
6617         cfg->generic_context = generic_context;
6618
6619         if (!cfg->generic_sharing_context)
6620                 g_assert (!sig->has_type_parameters);
6621
6622         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6623                 g_assert (method->is_inflated);
6624                 g_assert (mono_method_get_context (method)->method_inst);
6625         }
6626         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6627                 g_assert (sig->generic_param_count);
6628
6629         if (cfg->method == method) {
6630                 cfg->real_offset = 0;
6631         } else {
6632                 cfg->real_offset = inline_offset;
6633         }
6634
6635         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6636         cfg->cil_offset_to_bb_len = header->code_size;
6637
6638         cfg->current_method = method;
6639
6640         if (cfg->verbose_level > 2)
6641                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6642
6643         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6644         if (sig->hasthis)
6645                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6646         for (n = 0; n < sig->param_count; ++n)
6647                 param_types [n + sig->hasthis] = sig->params [n];
6648         cfg->arg_types = param_types;
6649
6650         dont_inline = g_list_prepend (dont_inline, method);
6651         if (cfg->method == method) {
6652
6653                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6654                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6655
6656                 /* ENTRY BLOCK */
6657                 NEW_BBLOCK (cfg, start_bblock);
6658                 cfg->bb_entry = start_bblock;
6659                 start_bblock->cil_code = NULL;
6660                 start_bblock->cil_length = 0;
6661 #if defined(__native_client_codegen__)
6662                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6663                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6664                 MONO_ADD_INS (start_bblock, ins);
6665 #endif
6666
6667                 /* EXIT BLOCK */
6668                 NEW_BBLOCK (cfg, end_bblock);
6669                 cfg->bb_exit = end_bblock;
6670                 end_bblock->cil_code = NULL;
6671                 end_bblock->cil_length = 0;
6672                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6673                 g_assert (cfg->num_bblocks == 2);
6674
6675                 arg_array = cfg->args;
6676
6677                 if (header->num_clauses) {
6678                         cfg->spvars = g_hash_table_new (NULL, NULL);
6679                         cfg->exvars = g_hash_table_new (NULL, NULL);
6680                 }
6681                 /* handle exception clauses */
6682                 for (i = 0; i < header->num_clauses; ++i) {
6683                         MonoBasicBlock *try_bb;
6684                         MonoExceptionClause *clause = &header->clauses [i];
6685                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6686                         try_bb->real_offset = clause->try_offset;
6687                         try_bb->try_start = TRUE;
6688                         try_bb->region = ((i + 1) << 8) | clause->flags;
6689                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6690                         tblock->real_offset = clause->handler_offset;
6691                         tblock->flags |= BB_EXCEPTION_HANDLER;
6692
6693                         link_bblock (cfg, try_bb, tblock);
6694
6695                         if (*(ip + clause->handler_offset) == CEE_POP)
6696                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6697
6698                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6699                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6700                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6701                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6702                                 MONO_ADD_INS (tblock, ins);
6703
6704                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6705                                         /* finally clauses already have a seq point */
6706                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6707                                         MONO_ADD_INS (tblock, ins);
6708                                 }
6709
6710                                 /* todo: is a fault block unsafe to optimize? */
6711                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6712                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
6713                         }
6714
6715
6716                         /*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);
6717                           while (p < end) {
6718                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
6719                           }*/
6720                         /* catch and filter blocks get the exception object on the stack */
6721                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
6722                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6723                                 MonoInst *dummy_use;
6724
6725                                 /* mostly like handle_stack_args (), but just sets the input args */
6726                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
6727                                 tblock->in_scount = 1;
6728                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6729                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6730
6731                                 /* 
6732                                  * Add a dummy use for the exvar so its liveness info will be
6733                                  * correct.
6734                                  */
6735                                 cfg->cbb = tblock;
6736                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
6737                                 
6738                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6739                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
6740                                         tblock->flags |= BB_EXCEPTION_HANDLER;
6741                                         tblock->real_offset = clause->data.filter_offset;
6742                                         tblock->in_scount = 1;
6743                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6744                                         /* The filter block shares the exvar with the handler block */
6745                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6746                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6747                                         MONO_ADD_INS (tblock, ins);
6748                                 }
6749                         }
6750
6751                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
6752                                         clause->data.catch_class &&
6753                                         cfg->generic_sharing_context &&
6754                                         mono_class_check_context_used (clause->data.catch_class)) {
6755                                 /*
6756                                  * In shared generic code with catch
6757                                  * clauses containing type variables
6758                                  * the exception handling code has to
6759                                  * be able to get to the rgctx.
6760                                  * Therefore we have to make sure that
6761                                  * the vtable/mrgctx argument (for
6762                                  * static or generic methods) or the
6763                                  * "this" argument (for non-static
6764                                  * methods) are live.
6765                                  */
6766                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6767                                                 mini_method_get_context (method)->method_inst ||
6768                                                 method->klass->valuetype) {
6769                                         mono_get_vtable_var (cfg);
6770                                 } else {
6771                                         MonoInst *dummy_use;
6772
6773                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
6774                                 }
6775                         }
6776                 }
6777         } else {
6778                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
6779                 cfg->cbb = start_bblock;
6780                 cfg->args = arg_array;
6781                 mono_save_args (cfg, sig, inline_args);
6782         }
6783
6784         /* FIRST CODE BLOCK */
6785         NEW_BBLOCK (cfg, bblock);
6786         bblock->cil_code = ip;
6787         cfg->cbb = bblock;
6788         cfg->ip = ip;
6789
6790         ADD_BBLOCK (cfg, bblock);
6791
6792         if (cfg->method == method) {
6793                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
6794                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
6795                         MONO_INST_NEW (cfg, ins, OP_BREAK);
6796                         MONO_ADD_INS (bblock, ins);
6797                 }
6798         }
6799
6800         if (mono_security_cas_enabled ())
6801                 secman = mono_security_manager_get_methods ();
6802
6803         security = (secman && mono_security_method_has_declsec (method));
6804         /* at this point having security doesn't mean we have any code to generate */
6805         if (security && (cfg->method == method)) {
6806                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
6807                  * And we do not want to enter the next section (with allocation) if we
6808                  * have nothing to generate */
6809                 security = mono_declsec_get_demands (method, &actions);
6810         }
6811
6812         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
6813         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
6814         if (pinvoke) {
6815                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6816                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6817                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
6818
6819                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
6820                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6821                                 pinvoke = FALSE;
6822                         }
6823                         if (custom)
6824                                 mono_custom_attrs_free (custom);
6825
6826                         if (pinvoke) {
6827                                 custom = mono_custom_attrs_from_class (wrapped->klass);
6828                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6829                                         pinvoke = FALSE;
6830                                 }
6831                                 if (custom)
6832                                         mono_custom_attrs_free (custom);
6833                         }
6834                 } else {
6835                         /* not a P/Invoke after all */
6836                         pinvoke = FALSE;
6837                 }
6838         }
6839         
6840         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
6841                 /* we use a separate basic block for the initialization code */
6842                 NEW_BBLOCK (cfg, init_localsbb);
6843                 cfg->bb_init = init_localsbb;
6844                 init_localsbb->real_offset = cfg->real_offset;
6845                 start_bblock->next_bb = init_localsbb;
6846                 init_localsbb->next_bb = bblock;
6847                 link_bblock (cfg, start_bblock, init_localsbb);
6848                 link_bblock (cfg, init_localsbb, bblock);
6849                 
6850                 cfg->cbb = init_localsbb;
6851         } else {
6852                 start_bblock->next_bb = bblock;
6853                 link_bblock (cfg, start_bblock, bblock);
6854         }
6855
6856         if (cfg->gsharedvt && cfg->method == method) {
6857                 MonoGSharedVtMethodInfo *info;
6858                 MonoInst *var, *locals_var;
6859                 int dreg;
6860
6861                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
6862                 info->method = cfg->method;
6863                 // FIXME: Free this
6864                 info->entries = g_ptr_array_new ();
6865                 cfg->gsharedvt_info = info;
6866
6867                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6868                 /* prevent it from being register allocated */
6869                 //var->flags |= MONO_INST_INDIRECT;
6870                 cfg->gsharedvt_info_var = var;
6871
6872                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
6873                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
6874
6875                 /* Allocate locals */
6876                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6877                 /* prevent it from being register allocated */
6878                 //locals_var->flags |= MONO_INST_INDIRECT;
6879                 cfg->gsharedvt_locals_var = locals_var;
6880
6881                 dreg = alloc_ireg (cfg);
6882                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
6883
6884                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
6885                 ins->dreg = locals_var->dreg;
6886                 ins->sreg1 = dreg;
6887                 MONO_ADD_INS (cfg->cbb, ins);
6888                 cfg->gsharedvt_locals_var_ins = ins;
6889                 
6890                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
6891                 /*
6892                 if (init_locals)
6893                         ins->flags |= MONO_INST_INIT;
6894                 */
6895         }
6896
6897         /* at this point we know, if security is TRUE, that some code needs to be generated */
6898         if (security && (cfg->method == method)) {
6899                 MonoInst *args [2];
6900
6901                 cfg->stat_cas_demand_generation++;
6902
6903                 if (actions.demand.blob) {
6904                         /* Add code for SecurityAction.Demand */
6905                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
6906                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
6907                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
6908                         mono_emit_method_call (cfg, secman->demand, args, NULL);
6909                 }
6910                 if (actions.noncasdemand.blob) {
6911                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
6912                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
6913                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
6914                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
6915                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
6916                         mono_emit_method_call (cfg, secman->demand, args, NULL);
6917                 }
6918                 if (actions.demandchoice.blob) {
6919                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
6920                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
6921                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
6922                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
6923                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
6924                 }
6925         }
6926
6927         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
6928         if (pinvoke) {
6929                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
6930         }
6931
6932         if (mono_security_core_clr_enabled ()) {
6933                 /* check if this is native code, e.g. an icall or a p/invoke */
6934                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
6935                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6936                         if (wrapped) {
6937                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
6938                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
6939
6940                                 /* if this ia a native call then it can only be JITted from platform code */
6941                                 if ((icall || pinvk) && method->klass && method->klass->image) {
6942                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
6943                                                 MonoException *ex = icall ? mono_get_exception_security () : 
6944                                                         mono_get_exception_method_access ();
6945                                                 emit_throw_exception (cfg, ex);
6946                                         }
6947                                 }
6948                         }
6949                 }
6950         }
6951
6952         if (header->code_size == 0)
6953                 UNVERIFIED;
6954
6955         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
6956                 ip = err_pos;
6957                 UNVERIFIED;
6958         }
6959
6960         if (cfg->method == method)
6961                 mono_debug_init_method (cfg, bblock, breakpoint_id);
6962
6963         for (n = 0; n < header->num_locals; ++n) {
6964                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
6965                         UNVERIFIED;
6966         }
6967         class_inits = NULL;
6968
6969         /* We force the vtable variable here for all shared methods
6970            for the possibility that they might show up in a stack
6971            trace where their exact instantiation is needed. */
6972         if (cfg->generic_sharing_context && method == cfg->method) {
6973                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6974                                 mini_method_get_context (method)->method_inst ||
6975                                 method->klass->valuetype) {
6976                         mono_get_vtable_var (cfg);
6977                 } else {
6978                         /* FIXME: Is there a better way to do this?
6979                            We need the variable live for the duration
6980                            of the whole method. */
6981                         cfg->args [0]->flags |= MONO_INST_INDIRECT;
6982                 }
6983         }
6984
6985         /* add a check for this != NULL to inlined methods */
6986         if (is_virtual_call) {
6987                 MonoInst *arg_ins;
6988
6989                 NEW_ARGLOAD (cfg, arg_ins, 0);
6990                 MONO_ADD_INS (cfg->cbb, arg_ins);
6991                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
6992         }
6993
6994         skip_dead_blocks = !dont_verify;
6995         if (skip_dead_blocks) {
6996                 original_bb = bb = mono_basic_block_split (method, &error);
6997                 if (!mono_error_ok (&error)) {
6998                         mono_error_cleanup (&error);
6999                         UNVERIFIED;
7000                 }
7001                 g_assert (bb);
7002         }
7003
7004         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7005         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7006
7007         ins_flag = 0;
7008         start_new_bblock = 0;
7009         cfg->cbb = bblock;
7010         while (ip < end) {
7011                 if (cfg->method == method)
7012                         cfg->real_offset = ip - header->code;
7013                 else
7014                         cfg->real_offset = inline_offset;
7015                 cfg->ip = ip;
7016
7017                 context_used = 0;
7018                 
7019                 if (start_new_bblock) {
7020                         bblock->cil_length = ip - bblock->cil_code;
7021                         if (start_new_bblock == 2) {
7022                                 g_assert (ip == tblock->cil_code);
7023                         } else {
7024                                 GET_BBLOCK (cfg, tblock, ip);
7025                         }
7026                         bblock->next_bb = tblock;
7027                         bblock = tblock;
7028                         cfg->cbb = bblock;
7029                         start_new_bblock = 0;
7030                         for (i = 0; i < bblock->in_scount; ++i) {
7031                                 if (cfg->verbose_level > 3)
7032                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7033                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7034                                 *sp++ = ins;
7035                         }
7036                         if (class_inits)
7037                                 g_slist_free (class_inits);
7038                         class_inits = NULL;
7039                 } else {
7040                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7041                                 link_bblock (cfg, bblock, tblock);
7042                                 if (sp != stack_start) {
7043                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7044                                         sp = stack_start;
7045                                         CHECK_UNVERIFIABLE (cfg);
7046                                 }
7047                                 bblock->next_bb = tblock;
7048                                 bblock = tblock;
7049                                 cfg->cbb = bblock;
7050                                 for (i = 0; i < bblock->in_scount; ++i) {
7051                                         if (cfg->verbose_level > 3)
7052                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7053                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7054                                         *sp++ = ins;
7055                                 }
7056                                 g_slist_free (class_inits);
7057                                 class_inits = NULL;
7058                         }
7059                 }
7060
7061                 if (skip_dead_blocks) {
7062                         int ip_offset = ip - header->code;
7063
7064                         if (ip_offset == bb->end)
7065                                 bb = bb->next;
7066
7067                         if (bb->dead) {
7068                                 int op_size = mono_opcode_size (ip, end);
7069                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7070
7071                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7072
7073                                 if (ip_offset + op_size == bb->end) {
7074                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7075                                         MONO_ADD_INS (bblock, ins);
7076                                         start_new_bblock = 1;
7077                                 }
7078
7079                                 ip += op_size;
7080                                 continue;
7081                         }
7082                 }
7083                 /*
7084                  * Sequence points are points where the debugger can place a breakpoint.
7085                  * Currently, we generate these automatically at points where the IL
7086                  * stack is empty.
7087                  */
7088                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7089                         /*
7090                          * Make methods interruptable at the beginning, and at the targets of
7091                          * backward branches.
7092                          * Also, do this at the start of every bblock in methods with clauses too,
7093                          * to be able to handle instructions with inprecise control flow like
7094                          * throw/endfinally.
7095                          * Backward branches are handled at the end of method-to-ir ().
7096                          */
7097                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7098
7099                         /* Avoid sequence points on empty IL like .volatile */
7100                         // FIXME: Enable this
7101                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7102                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7103                         MONO_ADD_INS (cfg->cbb, ins);
7104
7105                         if (sym_seq_points)
7106                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7107                 }
7108
7109                 bblock->real_offset = cfg->real_offset;
7110
7111                 if ((cfg->method == method) && cfg->coverage_info) {
7112                         guint32 cil_offset = ip - header->code;
7113                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7114
7115                         /* TODO: Use an increment here */
7116 #if defined(TARGET_X86)
7117                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7118                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7119                         ins->inst_imm = 1;
7120                         MONO_ADD_INS (cfg->cbb, ins);
7121 #else
7122                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7123                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7124 #endif
7125                 }
7126
7127                 if (cfg->verbose_level > 3)
7128                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7129
7130                 switch (*ip) {
7131                 case CEE_NOP:
7132                         if (seq_points && !sym_seq_points && sp != stack_start) {
7133                                 /*
7134                                  * The C# compiler uses these nops to notify the JIT that it should
7135                                  * insert seq points.
7136                                  */
7137                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7138                                 MONO_ADD_INS (cfg->cbb, ins);
7139                         }
7140                         if (cfg->keep_cil_nops)
7141                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7142                         else
7143                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7144                         ip++;
7145                         MONO_ADD_INS (bblock, ins);
7146                         break;
7147                 case CEE_BREAK:
7148                         if (should_insert_brekpoint (cfg->method)) {
7149                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7150                         } else {
7151                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7152                         }
7153                         ip++;
7154                         MONO_ADD_INS (bblock, ins);
7155                         break;
7156                 case CEE_LDARG_0:
7157                 case CEE_LDARG_1:
7158                 case CEE_LDARG_2:
7159                 case CEE_LDARG_3:
7160                         CHECK_STACK_OVF (1);
7161                         n = (*ip)-CEE_LDARG_0;
7162                         CHECK_ARG (n);
7163                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7164                         ip++;
7165                         *sp++ = ins;
7166                         break;
7167                 case CEE_LDLOC_0:
7168                 case CEE_LDLOC_1:
7169                 case CEE_LDLOC_2:
7170                 case CEE_LDLOC_3:
7171                         CHECK_STACK_OVF (1);
7172                         n = (*ip)-CEE_LDLOC_0;
7173                         CHECK_LOCAL (n);
7174                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7175                         ip++;
7176                         *sp++ = ins;
7177                         break;
7178                 case CEE_STLOC_0:
7179                 case CEE_STLOC_1:
7180                 case CEE_STLOC_2:
7181                 case CEE_STLOC_3: {
7182                         CHECK_STACK (1);
7183                         n = (*ip)-CEE_STLOC_0;
7184                         CHECK_LOCAL (n);
7185                         --sp;
7186                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7187                                 UNVERIFIED;
7188                         emit_stloc_ir (cfg, sp, header, n);
7189                         ++ip;
7190                         inline_costs += 1;
7191                         break;
7192                         }
7193                 case CEE_LDARG_S:
7194                         CHECK_OPSIZE (2);
7195                         CHECK_STACK_OVF (1);
7196                         n = ip [1];
7197                         CHECK_ARG (n);
7198                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7199                         *sp++ = ins;
7200                         ip += 2;
7201                         break;
7202                 case CEE_LDARGA_S:
7203                         CHECK_OPSIZE (2);
7204                         CHECK_STACK_OVF (1);
7205                         n = ip [1];
7206                         CHECK_ARG (n);
7207                         NEW_ARGLOADA (cfg, ins, n);
7208                         MONO_ADD_INS (cfg->cbb, ins);
7209                         *sp++ = ins;
7210                         ip += 2;
7211                         break;
7212                 case CEE_STARG_S:
7213                         CHECK_OPSIZE (2);
7214                         CHECK_STACK (1);
7215                         --sp;
7216                         n = ip [1];
7217                         CHECK_ARG (n);
7218                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7219                                 UNVERIFIED;
7220                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7221                         ip += 2;
7222                         break;
7223                 case CEE_LDLOC_S:
7224                         CHECK_OPSIZE (2);
7225                         CHECK_STACK_OVF (1);
7226                         n = ip [1];
7227                         CHECK_LOCAL (n);
7228                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7229                         *sp++ = ins;
7230                         ip += 2;
7231                         break;
7232                 case CEE_LDLOCA_S: {
7233                         unsigned char *tmp_ip;
7234                         CHECK_OPSIZE (2);
7235                         CHECK_STACK_OVF (1);
7236                         CHECK_LOCAL (ip [1]);
7237
7238                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7239                                 ip = tmp_ip;
7240                                 inline_costs += 1;
7241                                 break;
7242                         }
7243
7244                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7245                         *sp++ = ins;
7246                         ip += 2;
7247                         break;
7248                 }
7249                 case CEE_STLOC_S:
7250                         CHECK_OPSIZE (2);
7251                         CHECK_STACK (1);
7252                         --sp;
7253                         CHECK_LOCAL (ip [1]);
7254                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7255                                 UNVERIFIED;
7256                         emit_stloc_ir (cfg, sp, header, ip [1]);
7257                         ip += 2;
7258                         inline_costs += 1;
7259                         break;
7260                 case CEE_LDNULL:
7261                         CHECK_STACK_OVF (1);
7262                         EMIT_NEW_PCONST (cfg, ins, NULL);
7263                         ins->type = STACK_OBJ;
7264                         ++ip;
7265                         *sp++ = ins;
7266                         break;
7267                 case CEE_LDC_I4_M1:
7268                         CHECK_STACK_OVF (1);
7269                         EMIT_NEW_ICONST (cfg, ins, -1);
7270                         ++ip;
7271                         *sp++ = ins;
7272                         break;
7273                 case CEE_LDC_I4_0:
7274                 case CEE_LDC_I4_1:
7275                 case CEE_LDC_I4_2:
7276                 case CEE_LDC_I4_3:
7277                 case CEE_LDC_I4_4:
7278                 case CEE_LDC_I4_5:
7279                 case CEE_LDC_I4_6:
7280                 case CEE_LDC_I4_7:
7281                 case CEE_LDC_I4_8:
7282                         CHECK_STACK_OVF (1);
7283                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7284                         ++ip;
7285                         *sp++ = ins;
7286                         break;
7287                 case CEE_LDC_I4_S:
7288                         CHECK_OPSIZE (2);
7289                         CHECK_STACK_OVF (1);
7290                         ++ip;
7291                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7292                         ++ip;
7293                         *sp++ = ins;
7294                         break;
7295                 case CEE_LDC_I4:
7296                         CHECK_OPSIZE (5);
7297                         CHECK_STACK_OVF (1);
7298                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7299                         ip += 5;
7300                         *sp++ = ins;
7301                         break;
7302                 case CEE_LDC_I8:
7303                         CHECK_OPSIZE (9);
7304                         CHECK_STACK_OVF (1);
7305                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7306                         ins->type = STACK_I8;
7307                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7308                         ++ip;
7309                         ins->inst_l = (gint64)read64 (ip);
7310                         MONO_ADD_INS (bblock, ins);
7311                         ip += 8;
7312                         *sp++ = ins;
7313                         break;
7314                 case CEE_LDC_R4: {
7315                         float *f;
7316                         gboolean use_aotconst = FALSE;
7317
7318 #ifdef TARGET_POWERPC
7319                         /* FIXME: Clean this up */
7320                         if (cfg->compile_aot)
7321                                 use_aotconst = TRUE;
7322 #endif
7323
7324                         /* FIXME: we should really allocate this only late in the compilation process */
7325                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7326                         CHECK_OPSIZE (5);
7327                         CHECK_STACK_OVF (1);
7328
7329                         if (use_aotconst) {
7330                                 MonoInst *cons;
7331                                 int dreg;
7332
7333                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7334
7335                                 dreg = alloc_freg (cfg);
7336                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7337                                 ins->type = STACK_R8;
7338                         } else {
7339                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7340                                 ins->type = STACK_R8;
7341                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7342                                 ins->inst_p0 = f;
7343                                 MONO_ADD_INS (bblock, ins);
7344                         }
7345                         ++ip;
7346                         readr4 (ip, f);
7347                         ip += 4;
7348                         *sp++ = ins;                    
7349                         break;
7350                 }
7351                 case CEE_LDC_R8: {
7352                         double *d;
7353                         gboolean use_aotconst = FALSE;
7354
7355 #ifdef TARGET_POWERPC
7356                         /* FIXME: Clean this up */
7357                         if (cfg->compile_aot)
7358                                 use_aotconst = TRUE;
7359 #endif
7360
7361                         /* FIXME: we should really allocate this only late in the compilation process */
7362                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7363                         CHECK_OPSIZE (9);
7364                         CHECK_STACK_OVF (1);
7365
7366                         if (use_aotconst) {
7367                                 MonoInst *cons;
7368                                 int dreg;
7369
7370                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7371
7372                                 dreg = alloc_freg (cfg);
7373                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7374                                 ins->type = STACK_R8;
7375                         } else {
7376                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7377                                 ins->type = STACK_R8;
7378                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7379                                 ins->inst_p0 = d;
7380                                 MONO_ADD_INS (bblock, ins);
7381                         }
7382                         ++ip;
7383                         readr8 (ip, d);
7384                         ip += 8;
7385                         *sp++ = ins;
7386                         break;
7387                 }
7388                 case CEE_DUP: {
7389                         MonoInst *temp, *store;
7390                         CHECK_STACK (1);
7391                         CHECK_STACK_OVF (1);
7392                         sp--;
7393                         ins = *sp;
7394
7395                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7396                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7397
7398                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7399                         *sp++ = ins;
7400
7401                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7402                         *sp++ = ins;
7403
7404                         ++ip;
7405                         inline_costs += 2;
7406                         break;
7407                 }
7408                 case CEE_POP:
7409                         CHECK_STACK (1);
7410                         ip++;
7411                         --sp;
7412
7413 #ifdef TARGET_X86
7414                         if (sp [0]->type == STACK_R8)
7415                                 /* we need to pop the value from the x86 FP stack */
7416                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7417 #endif
7418                         break;
7419                 case CEE_JMP: {
7420                         MonoCallInst *call;
7421
7422                         INLINE_FAILURE ("jmp");
7423                         GSHAREDVT_FAILURE (*ip);
7424
7425                         CHECK_OPSIZE (5);
7426                         if (stack_start != sp)
7427                                 UNVERIFIED;
7428                         token = read32 (ip + 1);
7429                         /* FIXME: check the signature matches */
7430                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7431
7432                         if (!cmethod || mono_loader_get_last_error ())
7433                                 LOAD_ERROR;
7434  
7435                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7436                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7437
7438                         if (mono_security_cas_enabled ())
7439                                 CHECK_CFG_EXCEPTION;
7440
7441 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
7442                         {
7443                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7444                                 int i, n;
7445
7446                                 /* Handle tail calls similarly to calls */
7447                                 n = fsig->param_count + fsig->hasthis;
7448
7449                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7450                                 call->method = cmethod;
7451                                 call->tail_call = TRUE;
7452                                 call->signature = mono_method_signature (cmethod);
7453                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7454                                 call->inst.inst_p0 = cmethod;
7455                                 for (i = 0; i < n; ++i)
7456                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7457
7458                                 mono_arch_emit_call (cfg, call);
7459                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7460                         }
7461 #else
7462                         for (i = 0; i < num_args; ++i)
7463                                 /* Prevent arguments from being optimized away */
7464                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
7465
7466                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7467                         ins = (MonoInst*)call;
7468                         ins->inst_p0 = cmethod;
7469                         MONO_ADD_INS (bblock, ins);
7470 #endif
7471
7472                         ip += 5;
7473                         start_new_bblock = 1;
7474                         break;
7475                 }
7476                 case CEE_CALLI:
7477                 case CEE_CALL:
7478                 case CEE_CALLVIRT: {
7479                         MonoInst *addr = NULL;
7480                         MonoMethodSignature *fsig = NULL;
7481                         int array_rank = 0;
7482                         int virtual = *ip == CEE_CALLVIRT;
7483                         int calli = *ip == CEE_CALLI;
7484                         gboolean pass_imt_from_rgctx = FALSE;
7485                         MonoInst *imt_arg = NULL;
7486                         MonoInst *keep_this_alive = NULL;
7487                         gboolean pass_vtable = FALSE;
7488                         gboolean pass_mrgctx = FALSE;
7489                         MonoInst *vtable_arg = NULL;
7490                         gboolean check_this = FALSE;
7491                         gboolean supported_tail_call = FALSE;
7492                         gboolean tail_call = FALSE;
7493                         gboolean need_seq_point = FALSE;
7494                         guint32 call_opcode = *ip;
7495                         gboolean emit_widen = TRUE;
7496                         gboolean push_res = TRUE;
7497                         gboolean skip_ret = FALSE;
7498                         gboolean delegate_invoke = FALSE;
7499
7500                         CHECK_OPSIZE (5);
7501                         token = read32 (ip + 1);
7502
7503                         ins = NULL;
7504
7505                         if (calli) {
7506                                 //GSHAREDVT_FAILURE (*ip);
7507                                 cmethod = NULL;
7508                                 CHECK_STACK (1);
7509                                 --sp;
7510                                 addr = *sp;
7511                                 fsig = mini_get_signature (method, token, generic_context);
7512                                 n = fsig->param_count + fsig->hasthis;
7513
7514                                 if (method->dynamic && fsig->pinvoke) {
7515                                         MonoInst *args [3];
7516
7517                                         /*
7518                                          * This is a call through a function pointer using a pinvoke
7519                                          * signature. Have to create a wrapper and call that instead.
7520                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7521                                          * instead based on the signature.
7522                                          */
7523                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7524                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7525                                         args [2] = addr;
7526                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7527                                 }
7528                         } else {
7529                                 MonoMethod *cil_method;
7530
7531                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7532                                 cil_method = cmethod;
7533                                 
7534                                 if (constrained_call) {
7535                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7536                                                 if (cfg->verbose_level > 2)
7537                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7538                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7539                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7540                                                           cfg->generic_sharing_context)) {
7541                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7542                                                 }
7543                                         } else {
7544                                                 if (cfg->verbose_level > 2)
7545                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7546
7547                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7548                                                         /* 
7549                                                          * This is needed since get_method_constrained can't find 
7550                                                          * the method in klass representing a type var.
7551                                                          * The type var is guaranteed to be a reference type in this
7552                                                          * case.
7553                                                          */
7554                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7555                                                                 g_assert (!cmethod->klass->valuetype);
7556                                                 } else {
7557                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7558                                                 }
7559                                         }
7560                                 }
7561                                         
7562                                 if (!cmethod || mono_loader_get_last_error ())
7563                                         LOAD_ERROR;
7564                                 if (!dont_verify && !cfg->skip_visibility) {
7565                                         MonoMethod *target_method = cil_method;
7566                                         if (method->is_inflated) {
7567                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7568                                         }
7569                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7570                                                 !mono_method_can_access_method (method, cil_method))
7571                                                 METHOD_ACCESS_FAILURE;
7572                                 }
7573
7574                                 if (mono_security_core_clr_enabled ())
7575                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7576
7577                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7578                                         /* MS.NET seems to silently convert this to a callvirt */
7579                                         virtual = 1;
7580
7581                                 {
7582                                         /*
7583                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7584                                          * converts to a callvirt.
7585                                          *
7586                                          * tests/bug-515884.il is an example of this behavior
7587                                          */
7588                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7589                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7590                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7591                                                 virtual = 1;
7592                                 }
7593
7594                                 if (!cmethod->klass->inited)
7595                                         if (!mono_class_init (cmethod->klass))
7596                                                 TYPE_LOAD_ERROR (cmethod->klass);
7597
7598                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7599                                     mini_class_is_system_array (cmethod->klass)) {
7600                                         array_rank = cmethod->klass->rank;
7601                                         fsig = mono_method_signature (cmethod);
7602                                 } else {
7603                                         fsig = mono_method_signature (cmethod);
7604
7605                                         if (!fsig)
7606                                                 LOAD_ERROR;
7607
7608                                         if (fsig->pinvoke) {
7609                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7610                                                         check_for_pending_exc, FALSE);
7611                                                 fsig = mono_method_signature (wrapper);
7612                                         } else if (constrained_call) {
7613                                                 fsig = mono_method_signature (cmethod);
7614                                         } else {
7615                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7616                                         }
7617                                 }
7618
7619                                 mono_save_token_info (cfg, image, token, cil_method);
7620
7621                                 if (!MONO_TYPE_IS_VOID (fsig->ret) && !sym_seq_points) {
7622                                         /*
7623                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7624                                          * foo (bar (), baz ())
7625                                          * works correctly. MS does this also:
7626                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7627                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7628                                          * even for simple cases, like:
7629                                          * int i = foo ();
7630                                          */
7631                                         /* Special case a few common successor opcodes */
7632                                         if (!(ip + 5 < end && ip [5] == CEE_POP))
7633                                                 need_seq_point = TRUE;
7634                                 }
7635
7636                                 n = fsig->param_count + fsig->hasthis;
7637
7638                                 /* Don't support calls made using type arguments for now */
7639                                 /*
7640                                 if (cfg->gsharedvt) {
7641                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7642                                                 GSHAREDVT_FAILURE (*ip);
7643                                 }
7644                                 */
7645
7646                                 if (mono_security_cas_enabled ()) {
7647                                         if (check_linkdemand (cfg, method, cmethod))
7648                                                 INLINE_FAILURE ("linkdemand");
7649                                         CHECK_CFG_EXCEPTION;
7650                                 }
7651
7652                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7653                                         g_assert_not_reached ();
7654                         }
7655
7656                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7657                                 UNVERIFIED;
7658
7659                         if (!cfg->generic_sharing_context && cmethod)
7660                                 g_assert (!mono_method_check_context_used (cmethod));
7661
7662                         CHECK_STACK (n);
7663
7664                         //g_assert (!virtual || fsig->hasthis);
7665
7666                         sp -= n;
7667
7668                         if (constrained_call) {
7669                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7670                                         /*
7671                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7672                                          */
7673                                         /* Special case Object methods as they are easy to implement */
7674                                         if (cmethod->klass == mono_defaults.object_class) {
7675                                                 MonoInst *args [16];
7676
7677                                                 args [0] = sp [0];
7678                                                 EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7679                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7680
7681                                                 if (!strcmp (cmethod->name, "ToString")) {
7682                                                         ins = mono_emit_jit_icall (cfg, mono_object_tostring_gsharedvt, args);
7683                                                 } else if (!strcmp (cmethod->name, "Equals")) {
7684                                                         args [3] = sp [1];
7685                                                         ins = mono_emit_jit_icall (cfg, mono_object_equals_gsharedvt, args);
7686                                                 } else if (!strcmp (cmethod->name, "GetHashCode")) {
7687                                                         ins = mono_emit_jit_icall (cfg, mono_object_gethashcode_gsharedvt, args);
7688                                                 } else {
7689                                                         GSHAREDVT_FAILURE (*ip);
7690                                                 }
7691                                                 goto call_end;
7692                                         } else if (constrained_call->valuetype && cmethod->klass->valuetype) {
7693                                                 /* The 'Own method' case below */
7694                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && MONO_TYPE_IS_VOID (fsig->ret) && (fsig->param_count == 0 || (fsig->param_count == 1 && MONO_TYPE_IS_REFERENCE (fsig->params [0])))) {
7695                                                 MonoInst *args [16];
7696
7697                                                 args [0] = sp [0];
7698                                                 EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7699                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7700
7701                                                 if (fsig->param_count) {
7702                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7703                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7704                                                         ins->dreg = alloc_preg (cfg);
7705                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7706                                                         MONO_ADD_INS (cfg->cbb, ins);
7707                                                         args [3] = ins;
7708
7709                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [3]->dreg, 0, sp [1]->dreg);
7710                                                 } else {
7711                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
7712                                                 }
7713
7714                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
7715                                                 goto call_end;
7716                                         } else {
7717                                                 GSHAREDVT_FAILURE (*ip);
7718                                         }
7719                                 }
7720                                 /*
7721                                  * We have the `constrained.' prefix opcode.
7722                                  */
7723                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
7724                                         /*
7725                                          * The type parameter is instantiated as a valuetype,
7726                                          * but that type doesn't override the method we're
7727                                          * calling, so we need to box `this'.
7728                                          */
7729                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7730                                         ins->klass = constrained_call;
7731                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7732                                         CHECK_CFG_EXCEPTION;
7733                                 } else if (!constrained_call->valuetype) {
7734                                         int dreg = alloc_ireg_ref (cfg);
7735
7736                                         /*
7737                                          * The type parameter is instantiated as a reference
7738                                          * type.  We have a managed pointer on the stack, so
7739                                          * we need to dereference it here.
7740                                          */
7741                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
7742                                         ins->type = STACK_OBJ;
7743                                         sp [0] = ins;
7744                                 } else {
7745                                         if (cmethod->klass->valuetype) {
7746                                                 /* Own method */
7747                                         } else {
7748                                                 /* Interface method */
7749                                                 int ioffset, slot;
7750
7751                                                 mono_class_setup_vtable (constrained_call);
7752                                                 CHECK_TYPELOAD (constrained_call);
7753                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
7754                                                 if (ioffset == -1)
7755                                                         TYPE_LOAD_ERROR (constrained_call);
7756                                                 slot = mono_method_get_vtable_slot (cmethod);
7757                                                 if (slot == -1)
7758                                                         TYPE_LOAD_ERROR (cmethod->klass);
7759                                                 cmethod = constrained_call->vtable [ioffset + slot];
7760
7761                                                 if (cmethod->klass == mono_defaults.enum_class) {
7762                                                         /* Enum implements some interfaces, so treat this as the first case */
7763                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7764                                                         ins->klass = constrained_call;
7765                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7766                                                         CHECK_CFG_EXCEPTION;
7767                                                 }
7768                                         }
7769                                         virtual = 0;
7770                                 }
7771                                 constrained_call = NULL;
7772                         }
7773
7774                         if (!calli && check_call_signature (cfg, fsig, sp))
7775                                 UNVERIFIED;
7776
7777 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7778                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
7779                                 delegate_invoke = TRUE;
7780 #endif
7781
7782                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
7783                                 bblock = cfg->cbb;
7784                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7785                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7786                                         emit_widen = FALSE;
7787                                 }
7788
7789                                 goto call_end;
7790                         }
7791
7792                         /* 
7793                          * If the callee is a shared method, then its static cctor
7794                          * might not get called after the call was patched.
7795                          */
7796                         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)) {
7797                                 emit_generic_class_init (cfg, cmethod->klass);
7798                                 CHECK_TYPELOAD (cmethod->klass);
7799                         }
7800
7801                         if (cmethod)
7802                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
7803
7804                         if (cfg->generic_sharing_context && cmethod) {
7805                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
7806
7807                                 context_used = mini_method_check_context_used (cfg, cmethod);
7808
7809                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7810                                         /* Generic method interface
7811                                            calls are resolved via a
7812                                            helper function and don't
7813                                            need an imt. */
7814                                         if (!cmethod_context || !cmethod_context->method_inst)
7815                                                 pass_imt_from_rgctx = TRUE;
7816                                 }
7817
7818                                 /*
7819                                  * If a shared method calls another
7820                                  * shared method then the caller must
7821                                  * have a generic sharing context
7822                                  * because the magic trampoline
7823                                  * requires it.  FIXME: We shouldn't
7824                                  * have to force the vtable/mrgctx
7825                                  * variable here.  Instead there
7826                                  * should be a flag in the cfg to
7827                                  * request a generic sharing context.
7828                                  */
7829                                 if (context_used &&
7830                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
7831                                         mono_get_vtable_var (cfg);
7832                         }
7833
7834                         if (pass_vtable) {
7835                                 if (context_used) {
7836                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7837                                 } else {
7838                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7839
7840                                         CHECK_TYPELOAD (cmethod->klass);
7841                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7842                                 }
7843                         }
7844
7845                         if (pass_mrgctx) {
7846                                 g_assert (!vtable_arg);
7847
7848                                 if (!cfg->compile_aot) {
7849                                         /* 
7850                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
7851                                          * for type load errors before.
7852                                          */
7853                                         mono_class_setup_vtable (cmethod->klass);
7854                                         CHECK_TYPELOAD (cmethod->klass);
7855                                 }
7856
7857                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7858
7859                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
7860                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
7861                                          MONO_METHOD_IS_FINAL (cmethod)) &&
7862                                         !mono_class_is_marshalbyref (cmethod->klass)) {
7863                                         if (virtual)
7864                                                 check_this = TRUE;
7865                                         virtual = 0;
7866                                 }
7867                         }
7868
7869                         if (pass_imt_from_rgctx) {
7870                                 g_assert (!pass_vtable);
7871                                 g_assert (cmethod);
7872
7873                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
7874                                         cmethod, MONO_RGCTX_INFO_METHOD);
7875                         }
7876
7877                         if (check_this)
7878                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
7879
7880                         /* Calling virtual generic methods */
7881                         if (cmethod && virtual && 
7882                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
7883                             !(MONO_METHOD_IS_FINAL (cmethod) && 
7884                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
7885                             fsig->generic_param_count && 
7886                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
7887                                 MonoInst *this_temp, *this_arg_temp, *store;
7888                                 MonoInst *iargs [4];
7889                                 gboolean use_imt = FALSE;
7890
7891                                 g_assert (fsig->is_inflated);
7892
7893                                 /* Prevent inlining of methods that contain indirect calls */
7894                                 INLINE_FAILURE ("virtual generic call");
7895
7896                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7897                                         GSHAREDVT_FAILURE (*ip);
7898
7899 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
7900                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
7901                                         use_imt = TRUE;
7902 #endif
7903
7904                                 if (use_imt) {
7905                                         g_assert (!imt_arg);
7906                                         if (!context_used)
7907                                                 g_assert (cmethod->is_inflated);
7908                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
7909                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
7910                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
7911                                 } else {
7912                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
7913                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
7914                                         MONO_ADD_INS (bblock, store);
7915
7916                                         /* FIXME: This should be a managed pointer */
7917                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7918
7919                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
7920                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
7921                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
7922                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
7923                                         addr = mono_emit_jit_icall (cfg,
7924                                                                                                 mono_helper_compile_generic_method, iargs);
7925
7926                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
7927
7928                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
7929                                 }
7930
7931                                 goto call_end;
7932                         }
7933
7934                         /*
7935                          * Implement a workaround for the inherent races involved in locking:
7936                          * Monitor.Enter ()
7937                          * try {
7938                          * } finally {
7939                          *    Monitor.Exit ()
7940                          * }
7941                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
7942                          * try block, the Exit () won't be executed, see:
7943                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
7944                          * To work around this, we extend such try blocks to include the last x bytes
7945                          * of the Monitor.Enter () call.
7946                          */
7947                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
7948                                 MonoBasicBlock *tbb;
7949
7950                                 GET_BBLOCK (cfg, tbb, ip + 5);
7951                                 /* 
7952                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
7953                                  * from Monitor.Enter like ArgumentNullException.
7954                                  */
7955                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
7956                                         /* Mark this bblock as needing to be extended */
7957                                         tbb->extend_try_block = TRUE;
7958                                 }
7959                         }
7960
7961                         /* Conversion to a JIT intrinsic */
7962                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
7963                                 bblock = cfg->cbb;
7964                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7965                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7966                                         emit_widen = FALSE;
7967                                 }
7968                                 goto call_end;
7969                         }
7970
7971                         /* Inlining */
7972                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
7973                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
7974                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
7975                                  !g_list_find (dont_inline, cmethod)) {
7976                                 int costs;
7977                                 gboolean always = FALSE;
7978
7979                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7980                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7981                                         /* Prevent inlining of methods that call wrappers */
7982                                         INLINE_FAILURE ("wrapper call");
7983                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
7984                                         always = TRUE;
7985                                 }
7986
7987                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
7988                                 if (costs) {
7989                                         cfg->real_offset += 5;
7990                                         bblock = cfg->cbb;
7991
7992                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7993                                                 /* *sp is already set by inline_method */
7994                                                 sp++;
7995                                                 push_res = FALSE;
7996                                         }
7997
7998                                         inline_costs += costs;
7999
8000                                         goto call_end;
8001                                 }
8002                         }
8003
8004                         /* Tail recursion elimination */
8005                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8006                                 gboolean has_vtargs = FALSE;
8007                                 int i;
8008
8009                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8010                                 INLINE_FAILURE ("tail call");
8011
8012                                 /* keep it simple */
8013                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8014                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8015                                                 has_vtargs = TRUE;
8016                                 }
8017
8018                                 if (!has_vtargs) {
8019                                         for (i = 0; i < n; ++i)
8020                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8021                                         MONO_INST_NEW (cfg, ins, OP_BR);
8022                                         MONO_ADD_INS (bblock, ins);
8023                                         tblock = start_bblock->out_bb [0];
8024                                         link_bblock (cfg, bblock, tblock);
8025                                         ins->inst_target_bb = tblock;
8026                                         start_new_bblock = 1;
8027
8028                                         /* skip the CEE_RET, too */
8029                                         if (ip_in_bb (cfg, bblock, ip + 5))
8030                                                 skip_ret = TRUE;
8031                                         push_res = FALSE;
8032                                         goto call_end;
8033                                 }
8034                         }
8035
8036                         inline_costs += 10 * num_calls++;
8037
8038                         /*
8039                          * Making generic calls out of gsharedvt methods.
8040                          */
8041                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8042                                 MonoRgctxInfoType info_type;
8043
8044                                 if (virtual) {
8045                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8046                                                 //GSHAREDVT_FAILURE (*ip);
8047                                         // disable for possible remoting calls
8048                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8049                                                 GSHAREDVT_FAILURE (*ip);
8050                                         if (fsig->generic_param_count) {
8051                                                 /* virtual generic call */
8052                                                 g_assert (mono_use_imt);
8053                                                 g_assert (!imt_arg);
8054                                                 /* Same as the virtual generic case above */
8055                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8056                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8057                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8058                                                 vtable_arg = NULL;
8059                                         }
8060                                 }
8061
8062                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8063                                         /* test_0_multi_dim_arrays () in gshared.cs */
8064                                         GSHAREDVT_FAILURE (*ip);
8065
8066                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8067                                         keep_this_alive = sp [0];
8068
8069                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8070                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8071                                 else
8072                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8073                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8074
8075                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8076                                 goto call_end;
8077                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8078                                 /*
8079                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8080                                  */
8081                                 MonoInst *callee = addr;
8082
8083                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8084                                         /* Not tested */
8085                                         GSHAREDVT_FAILURE (*ip);
8086
8087                                 addr = emit_get_rgctx_sig (cfg, context_used,
8088                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8089                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8090                                 goto call_end;
8091                         }
8092
8093                         /* Generic sharing */
8094                         /* FIXME: only do this for generic methods if
8095                            they are not shared! */
8096                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8097                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8098                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8099                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8100                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8101                                 INLINE_FAILURE ("gshared");
8102
8103                                 g_assert (cfg->generic_sharing_context && cmethod);
8104                                 g_assert (!addr);
8105
8106                                 /*
8107                                  * We are compiling a call to a
8108                                  * generic method from shared code,
8109                                  * which means that we have to look up
8110                                  * the method in the rgctx and do an
8111                                  * indirect call.
8112                                  */
8113                                 if (fsig->hasthis)
8114                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8115
8116                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8117                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8118                                 goto call_end;
8119                         }
8120
8121                         /* Indirect calls */
8122                         if (addr) {
8123                                 if (call_opcode == CEE_CALL)
8124                                         g_assert (context_used);
8125                                 else if (call_opcode == CEE_CALLI)
8126                                         g_assert (!vtable_arg);
8127                                 else
8128                                         /* FIXME: what the hell is this??? */
8129                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8130                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8131
8132                                 /* Prevent inlining of methods with indirect calls */
8133                                 INLINE_FAILURE ("indirect call");
8134
8135                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8136                                         int info_type;
8137                                         gpointer info_data;
8138
8139                                         /* 
8140                                          * Instead of emitting an indirect call, emit a direct call
8141                                          * with the contents of the aotconst as the patch info.
8142                                          */
8143                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8144                                                 info_type = addr->inst_c1;
8145                                                 info_data = addr->inst_p0;
8146                                         } else {
8147                                                 info_type = addr->inst_right->inst_c1;
8148                                                 info_data = addr->inst_right->inst_left;
8149                                         }
8150                                         
8151                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8152                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8153                                                 NULLIFY_INS (addr);
8154                                                 goto call_end;
8155                                         }
8156                                 }
8157                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8158                                 goto call_end;
8159                         }
8160                                         
8161                         /* Array methods */
8162                         if (array_rank) {
8163                                 MonoInst *addr;
8164
8165                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8166                                         MonoInst *val = sp [fsig->param_count];
8167
8168                                         if (val->type == STACK_OBJ) {
8169                                                 MonoInst *iargs [2];
8170
8171                                                 iargs [0] = sp [0];
8172                                                 iargs [1] = val;
8173                                                 
8174                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8175                                         }
8176                                         
8177                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8178                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8179                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8180                                                 emit_write_barrier (cfg, addr, val);
8181                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8182                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8183
8184                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8185                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8186                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8187                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8188                                         CHECK_TYPELOAD (cmethod->klass);
8189                                         
8190                                         readonly = FALSE;
8191                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8192                                         ins = addr;
8193                                 } else {
8194                                         g_assert_not_reached ();
8195                                 }
8196
8197                                 emit_widen = FALSE;
8198                                 goto call_end;
8199                         }
8200
8201                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8202                         if (ins)
8203                                 goto call_end;
8204
8205                         /* Tail prefix / tail call optimization */
8206
8207                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8208                         /* FIXME: runtime generic context pointer for jumps? */
8209                         /* FIXME: handle this for generic sharing eventually */
8210                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8211                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig))
8212                                 supported_tail_call = TRUE;
8213                         if (supported_tail_call) {
8214                                 if (call_opcode != CEE_CALL)
8215                                         supported_tail_call = FALSE;
8216                         }
8217
8218                         if (supported_tail_call) {
8219                                 MonoCallInst *call;
8220
8221                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8222                                 INLINE_FAILURE ("tail call");
8223
8224                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8225
8226                                 if (ARCH_USE_OP_TAIL_CALL) {
8227                                         /* Handle tail calls similarly to normal calls */
8228                                         tail_call = TRUE;
8229                                 } else {
8230                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8231                                         call->tail_call = TRUE;
8232                                         call->method = cmethod;
8233                                         call->signature = mono_method_signature (cmethod);
8234
8235                                         /*
8236                                          * We implement tail calls by storing the actual arguments into the 
8237                                          * argument variables, then emitting a CEE_JMP.
8238                                          */
8239                                         for (i = 0; i < n; ++i) {
8240                                                 /* Prevent argument from being register allocated */
8241                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8242                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8243                                         }
8244                                         ins = (MonoInst*)call;
8245                                         ins->inst_p0 = cmethod;
8246                                         ins->inst_p1 = arg_array [0];
8247                                         MONO_ADD_INS (bblock, ins);
8248                                         link_bblock (cfg, bblock, end_bblock);                  
8249                                         start_new_bblock = 1;
8250
8251                                         // FIXME: Eliminate unreachable epilogs
8252
8253                                         /*
8254                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8255                                          * only reachable from this call.
8256                                          */
8257                                         GET_BBLOCK (cfg, tblock, ip + 5);
8258                                         if (tblock == bblock || tblock->in_count == 0)
8259                                                 skip_ret = TRUE;
8260                                         push_res = FALSE;
8261
8262                                         goto call_end;
8263                                 }
8264                         }
8265
8266                         /* 
8267                          * Synchronized wrappers.
8268                          * Its hard to determine where to replace a method with its synchronized
8269                          * wrapper without causing an infinite recursion. The current solution is
8270                          * to add the synchronized wrapper in the trampolines, and to
8271                          * change the called method to a dummy wrapper, and resolve that wrapper
8272                          * to the real method in mono_jit_compile_method ().
8273                          */
8274                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8275                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8276                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8277                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8278                         }
8279
8280                         /* Common call */
8281                         INLINE_FAILURE ("call");
8282                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8283                                                                                           imt_arg, vtable_arg);
8284
8285                         if (tail_call) {
8286                                 link_bblock (cfg, bblock, end_bblock);                  
8287                                 start_new_bblock = 1;
8288
8289                                 // FIXME: Eliminate unreachable epilogs
8290
8291                                 /*
8292                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8293                                  * only reachable from this call.
8294                                  */
8295                                 GET_BBLOCK (cfg, tblock, ip + 5);
8296                                 if (tblock == bblock || tblock->in_count == 0)
8297                                         skip_ret = TRUE;
8298                                 push_res = FALSE;
8299                         }
8300
8301                         call_end:
8302
8303                         /* End of call, INS should contain the result of the call, if any */
8304
8305                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8306                                 g_assert (ins);
8307                                 if (emit_widen)
8308                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8309                                 else
8310                                         *sp++ = ins;
8311                         }
8312
8313                         if (keep_this_alive) {
8314                                 MonoInst *dummy_use;
8315
8316                                 /* See mono_emit_method_call_full () */
8317                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8318                         }
8319
8320                         CHECK_CFG_EXCEPTION;
8321
8322                         ip += 5;
8323                         if (skip_ret) {
8324                                 g_assert (*ip == CEE_RET);
8325                                 ip += 1;
8326                         }
8327                         ins_flag = 0;
8328                         constrained_call = NULL;
8329                         if (need_seq_point)
8330                                 emit_seq_point (cfg, method, ip, FALSE);
8331                         break;
8332                 }
8333                 case CEE_RET:
8334                         if (cfg->method != method) {
8335                                 /* return from inlined method */
8336                                 /* 
8337                                  * If in_count == 0, that means the ret is unreachable due to
8338                                  * being preceeded by a throw. In that case, inline_method () will
8339                                  * handle setting the return value 
8340                                  * (test case: test_0_inline_throw ()).
8341                                  */
8342                                 if (return_var && cfg->cbb->in_count) {
8343                                         MonoType *ret_type = mono_method_signature (method)->ret;
8344
8345                                         MonoInst *store;
8346                                         CHECK_STACK (1);
8347                                         --sp;
8348
8349                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8350                                                 UNVERIFIED;
8351
8352                                         //g_assert (returnvar != -1);
8353                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8354                                         cfg->ret_var_set = TRUE;
8355                                 } 
8356                         } else {
8357                                 if (cfg->lmf_var && cfg->cbb->in_count)
8358                                         emit_pop_lmf (cfg);
8359
8360                                 if (cfg->ret) {
8361                                         MonoType *ret_type = mono_method_signature (method)->ret;
8362
8363                                         if (seq_points && !sym_seq_points) {
8364                                                 /* 
8365                                                  * Place a seq point here too even through the IL stack is not
8366                                                  * empty, so a step over on
8367                                                  * call <FOO>
8368                                                  * ret
8369                                                  * will work correctly.
8370                                                  */
8371                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8372                                                 MONO_ADD_INS (cfg->cbb, ins);
8373                                         }
8374
8375                                         g_assert (!return_var);
8376                                         CHECK_STACK (1);
8377                                         --sp;
8378
8379                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8380                                                 UNVERIFIED;
8381
8382                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8383                                                 MonoInst *ret_addr;
8384
8385                                                 if (!cfg->vret_addr) {
8386                                                         MonoInst *ins;
8387
8388                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8389                                                 } else {
8390                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8391
8392                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8393                                                         ins->klass = mono_class_from_mono_type (ret_type);
8394                                                 }
8395                                         } else {
8396 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8397                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8398                                                         MonoInst *iargs [1];
8399                                                         MonoInst *conv;
8400
8401                                                         iargs [0] = *sp;
8402                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8403                                                         mono_arch_emit_setret (cfg, method, conv);
8404                                                 } else {
8405                                                         mono_arch_emit_setret (cfg, method, *sp);
8406                                                 }
8407 #else
8408                                                 mono_arch_emit_setret (cfg, method, *sp);
8409 #endif
8410                                         }
8411                                 }
8412                         }
8413                         if (sp != stack_start)
8414                                 UNVERIFIED;
8415                         MONO_INST_NEW (cfg, ins, OP_BR);
8416                         ip++;
8417                         ins->inst_target_bb = end_bblock;
8418                         MONO_ADD_INS (bblock, ins);
8419                         link_bblock (cfg, bblock, end_bblock);
8420                         start_new_bblock = 1;
8421                         break;
8422                 case CEE_BR_S:
8423                         CHECK_OPSIZE (2);
8424                         MONO_INST_NEW (cfg, ins, OP_BR);
8425                         ip++;
8426                         target = ip + 1 + (signed char)(*ip);
8427                         ++ip;
8428                         GET_BBLOCK (cfg, tblock, target);
8429                         link_bblock (cfg, bblock, tblock);
8430                         ins->inst_target_bb = tblock;
8431                         if (sp != stack_start) {
8432                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8433                                 sp = stack_start;
8434                                 CHECK_UNVERIFIABLE (cfg);
8435                         }
8436                         MONO_ADD_INS (bblock, ins);
8437                         start_new_bblock = 1;
8438                         inline_costs += BRANCH_COST;
8439                         break;
8440                 case CEE_BEQ_S:
8441                 case CEE_BGE_S:
8442                 case CEE_BGT_S:
8443                 case CEE_BLE_S:
8444                 case CEE_BLT_S:
8445                 case CEE_BNE_UN_S:
8446                 case CEE_BGE_UN_S:
8447                 case CEE_BGT_UN_S:
8448                 case CEE_BLE_UN_S:
8449                 case CEE_BLT_UN_S:
8450                         CHECK_OPSIZE (2);
8451                         CHECK_STACK (2);
8452                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8453                         ip++;
8454                         target = ip + 1 + *(signed char*)ip;
8455                         ip++;
8456
8457                         ADD_BINCOND (NULL);
8458
8459                         sp = stack_start;
8460                         inline_costs += BRANCH_COST;
8461                         break;
8462                 case CEE_BR:
8463                         CHECK_OPSIZE (5);
8464                         MONO_INST_NEW (cfg, ins, OP_BR);
8465                         ip++;
8466
8467                         target = ip + 4 + (gint32)read32(ip);
8468                         ip += 4;
8469                         GET_BBLOCK (cfg, tblock, target);
8470                         link_bblock (cfg, bblock, tblock);
8471                         ins->inst_target_bb = tblock;
8472                         if (sp != stack_start) {
8473                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8474                                 sp = stack_start;
8475                                 CHECK_UNVERIFIABLE (cfg);
8476                         }
8477
8478                         MONO_ADD_INS (bblock, ins);
8479
8480                         start_new_bblock = 1;
8481                         inline_costs += BRANCH_COST;
8482                         break;
8483                 case CEE_BRFALSE_S:
8484                 case CEE_BRTRUE_S:
8485                 case CEE_BRFALSE:
8486                 case CEE_BRTRUE: {
8487                         MonoInst *cmp;
8488                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8489                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8490                         guint32 opsize = is_short ? 1 : 4;
8491
8492                         CHECK_OPSIZE (opsize);
8493                         CHECK_STACK (1);
8494                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8495                                 UNVERIFIED;
8496                         ip ++;
8497                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8498                         ip += opsize;
8499
8500                         sp--;
8501
8502                         GET_BBLOCK (cfg, tblock, target);
8503                         link_bblock (cfg, bblock, tblock);
8504                         GET_BBLOCK (cfg, tblock, ip);
8505                         link_bblock (cfg, bblock, tblock);
8506
8507                         if (sp != stack_start) {
8508                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8509                                 CHECK_UNVERIFIABLE (cfg);
8510                         }
8511
8512                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8513                         cmp->sreg1 = sp [0]->dreg;
8514                         type_from_op (cmp, sp [0], NULL);
8515                         CHECK_TYPE (cmp);
8516
8517 #if SIZEOF_REGISTER == 4
8518                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8519                                 /* Convert it to OP_LCOMPARE */
8520                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8521                                 ins->type = STACK_I8;
8522                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8523                                 ins->inst_l = 0;
8524                                 MONO_ADD_INS (bblock, ins);
8525                                 cmp->opcode = OP_LCOMPARE;
8526                                 cmp->sreg2 = ins->dreg;
8527                         }
8528 #endif
8529                         MONO_ADD_INS (bblock, cmp);
8530
8531                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8532                         type_from_op (ins, sp [0], NULL);
8533                         MONO_ADD_INS (bblock, ins);
8534                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8535                         GET_BBLOCK (cfg, tblock, target);
8536                         ins->inst_true_bb = tblock;
8537                         GET_BBLOCK (cfg, tblock, ip);
8538                         ins->inst_false_bb = tblock;
8539                         start_new_bblock = 2;
8540
8541                         sp = stack_start;
8542                         inline_costs += BRANCH_COST;
8543                         break;
8544                 }
8545                 case CEE_BEQ:
8546                 case CEE_BGE:
8547                 case CEE_BGT:
8548                 case CEE_BLE:
8549                 case CEE_BLT:
8550                 case CEE_BNE_UN:
8551                 case CEE_BGE_UN:
8552                 case CEE_BGT_UN:
8553                 case CEE_BLE_UN:
8554                 case CEE_BLT_UN:
8555                         CHECK_OPSIZE (5);
8556                         CHECK_STACK (2);
8557                         MONO_INST_NEW (cfg, ins, *ip);
8558                         ip++;
8559                         target = ip + 4 + (gint32)read32(ip);
8560                         ip += 4;
8561
8562                         ADD_BINCOND (NULL);
8563
8564                         sp = stack_start;
8565                         inline_costs += BRANCH_COST;
8566                         break;
8567                 case CEE_SWITCH: {
8568                         MonoInst *src1;
8569                         MonoBasicBlock **targets;
8570                         MonoBasicBlock *default_bblock;
8571                         MonoJumpInfoBBTable *table;
8572                         int offset_reg = alloc_preg (cfg);
8573                         int target_reg = alloc_preg (cfg);
8574                         int table_reg = alloc_preg (cfg);
8575                         int sum_reg = alloc_preg (cfg);
8576                         gboolean use_op_switch;
8577
8578                         CHECK_OPSIZE (5);
8579                         CHECK_STACK (1);
8580                         n = read32 (ip + 1);
8581                         --sp;
8582                         src1 = sp [0];
8583                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8584                                 UNVERIFIED;
8585
8586                         ip += 5;
8587                         CHECK_OPSIZE (n * sizeof (guint32));
8588                         target = ip + n * sizeof (guint32);
8589
8590                         GET_BBLOCK (cfg, default_bblock, target);
8591                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8592
8593                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8594                         for (i = 0; i < n; ++i) {
8595                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8596                                 targets [i] = tblock;
8597                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8598                                 ip += 4;
8599                         }
8600
8601                         if (sp != stack_start) {
8602                                 /* 
8603                                  * Link the current bb with the targets as well, so handle_stack_args
8604                                  * will set their in_stack correctly.
8605                                  */
8606                                 link_bblock (cfg, bblock, default_bblock);
8607                                 for (i = 0; i < n; ++i)
8608                                         link_bblock (cfg, bblock, targets [i]);
8609
8610                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8611                                 sp = stack_start;
8612                                 CHECK_UNVERIFIABLE (cfg);
8613                         }
8614
8615                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8616                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8617                         bblock = cfg->cbb;
8618
8619                         for (i = 0; i < n; ++i)
8620                                 link_bblock (cfg, bblock, targets [i]);
8621
8622                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8623                         table->table = targets;
8624                         table->table_size = n;
8625
8626                         use_op_switch = FALSE;
8627 #ifdef TARGET_ARM
8628                         /* ARM implements SWITCH statements differently */
8629                         /* FIXME: Make it use the generic implementation */
8630                         if (!cfg->compile_aot)
8631                                 use_op_switch = TRUE;
8632 #endif
8633
8634                         if (COMPILE_LLVM (cfg))
8635                                 use_op_switch = TRUE;
8636
8637                         cfg->cbb->has_jump_table = 1;
8638
8639                         if (use_op_switch) {
8640                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8641                                 ins->sreg1 = src1->dreg;
8642                                 ins->inst_p0 = table;
8643                                 ins->inst_many_bb = targets;
8644                                 ins->klass = GUINT_TO_POINTER (n);
8645                                 MONO_ADD_INS (cfg->cbb, ins);
8646                         } else {
8647                                 if (sizeof (gpointer) == 8)
8648                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8649                                 else
8650                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8651
8652 #if SIZEOF_REGISTER == 8
8653                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8654                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8655 #endif
8656
8657                                 if (cfg->compile_aot) {
8658                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8659                                 } else {
8660                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8661                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8662                                         ins->inst_p0 = table;
8663                                         ins->dreg = table_reg;
8664                                         MONO_ADD_INS (cfg->cbb, ins);
8665                                 }
8666
8667                                 /* FIXME: Use load_memindex */
8668                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8669                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8670                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8671                         }
8672                         start_new_bblock = 1;
8673                         inline_costs += (BRANCH_COST * 2);
8674                         break;
8675                 }
8676                 case CEE_LDIND_I1:
8677                 case CEE_LDIND_U1:
8678                 case CEE_LDIND_I2:
8679                 case CEE_LDIND_U2:
8680                 case CEE_LDIND_I4:
8681                 case CEE_LDIND_U4:
8682                 case CEE_LDIND_I8:
8683                 case CEE_LDIND_I:
8684                 case CEE_LDIND_R4:
8685                 case CEE_LDIND_R8:
8686                 case CEE_LDIND_REF:
8687                         CHECK_STACK (1);
8688                         --sp;
8689
8690                         switch (*ip) {
8691                         case CEE_LDIND_R4:
8692                         case CEE_LDIND_R8:
8693                                 dreg = alloc_freg (cfg);
8694                                 break;
8695                         case CEE_LDIND_I8:
8696                                 dreg = alloc_lreg (cfg);
8697                                 break;
8698                         case CEE_LDIND_REF:
8699                                 dreg = alloc_ireg_ref (cfg);
8700                                 break;
8701                         default:
8702                                 dreg = alloc_preg (cfg);
8703                         }
8704
8705                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
8706                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
8707                         ins->flags |= ins_flag;
8708                         ins_flag = 0;
8709                         MONO_ADD_INS (bblock, ins);
8710                         *sp++ = ins;
8711                         if (ins->flags & MONO_INST_VOLATILE) {
8712                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
8713                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8714                                 emit_memory_barrier (cfg, FullBarrier);
8715                         }
8716                         ++ip;
8717                         break;
8718                 case CEE_STIND_REF:
8719                 case CEE_STIND_I1:
8720                 case CEE_STIND_I2:
8721                 case CEE_STIND_I4:
8722                 case CEE_STIND_I8:
8723                 case CEE_STIND_R4:
8724                 case CEE_STIND_R8:
8725                 case CEE_STIND_I:
8726                         CHECK_STACK (2);
8727                         sp -= 2;
8728
8729                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
8730                         ins->flags |= ins_flag;
8731                         ins_flag = 0;
8732
8733                         if (ins->flags & MONO_INST_VOLATILE) {
8734                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
8735                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8736                                 emit_memory_barrier (cfg, FullBarrier);
8737                         }
8738
8739                         MONO_ADD_INS (bblock, ins);
8740
8741                         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)))
8742                                 emit_write_barrier (cfg, sp [0], sp [1]);
8743
8744                         inline_costs += 1;
8745                         ++ip;
8746                         break;
8747
8748                 case CEE_MUL:
8749                         CHECK_STACK (2);
8750
8751                         MONO_INST_NEW (cfg, ins, (*ip));
8752                         sp -= 2;
8753                         ins->sreg1 = sp [0]->dreg;
8754                         ins->sreg2 = sp [1]->dreg;
8755                         type_from_op (ins, sp [0], sp [1]);
8756                         CHECK_TYPE (ins);
8757                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8758
8759                         /* Use the immediate opcodes if possible */
8760                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
8761                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8762                                 if (imm_opcode != -1) {
8763                                         ins->opcode = imm_opcode;
8764                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
8765                                         ins->sreg2 = -1;
8766
8767                                         sp [1]->opcode = OP_NOP;
8768                                 }
8769                         }
8770
8771                         MONO_ADD_INS ((cfg)->cbb, (ins));
8772
8773                         *sp++ = mono_decompose_opcode (cfg, ins);
8774                         ip++;
8775                         break;
8776                 case CEE_ADD:
8777                 case CEE_SUB:
8778                 case CEE_DIV:
8779                 case CEE_DIV_UN:
8780                 case CEE_REM:
8781                 case CEE_REM_UN:
8782                 case CEE_AND:
8783                 case CEE_OR:
8784                 case CEE_XOR:
8785                 case CEE_SHL:
8786                 case CEE_SHR:
8787                 case CEE_SHR_UN:
8788                         CHECK_STACK (2);
8789
8790                         MONO_INST_NEW (cfg, ins, (*ip));
8791                         sp -= 2;
8792                         ins->sreg1 = sp [0]->dreg;
8793                         ins->sreg2 = sp [1]->dreg;
8794                         type_from_op (ins, sp [0], sp [1]);
8795                         CHECK_TYPE (ins);
8796                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
8797                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8798
8799                         /* FIXME: Pass opcode to is_inst_imm */
8800
8801                         /* Use the immediate opcodes if possible */
8802                         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)) {
8803                                 int imm_opcode;
8804
8805                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8806 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
8807                                 /* Keep emulated opcodes which are optimized away later */
8808                                 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) {
8809                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
8810                                 }
8811 #endif
8812                                 if (imm_opcode != -1) {
8813                                         ins->opcode = imm_opcode;
8814                                         if (sp [1]->opcode == OP_I8CONST) {
8815 #if SIZEOF_REGISTER == 8
8816                                                 ins->inst_imm = sp [1]->inst_l;
8817 #else
8818                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
8819                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
8820 #endif
8821                                         }
8822                                         else
8823                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
8824                                         ins->sreg2 = -1;
8825
8826                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
8827                                         if (sp [1]->next == NULL)
8828                                                 sp [1]->opcode = OP_NOP;
8829                                 }
8830                         }
8831                         MONO_ADD_INS ((cfg)->cbb, (ins));
8832
8833                         *sp++ = mono_decompose_opcode (cfg, ins);
8834                         ip++;
8835                         break;
8836                 case CEE_NEG:
8837                 case CEE_NOT:
8838                 case CEE_CONV_I1:
8839                 case CEE_CONV_I2:
8840                 case CEE_CONV_I4:
8841                 case CEE_CONV_R4:
8842                 case CEE_CONV_R8:
8843                 case CEE_CONV_U4:
8844                 case CEE_CONV_I8:
8845                 case CEE_CONV_U8:
8846                 case CEE_CONV_OVF_I8:
8847                 case CEE_CONV_OVF_U8:
8848                 case CEE_CONV_R_UN:
8849                         CHECK_STACK (1);
8850
8851                         /* Special case this earlier so we have long constants in the IR */
8852                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
8853                                 int data = sp [-1]->inst_c0;
8854                                 sp [-1]->opcode = OP_I8CONST;
8855                                 sp [-1]->type = STACK_I8;
8856 #if SIZEOF_REGISTER == 8
8857                                 if ((*ip) == CEE_CONV_U8)
8858                                         sp [-1]->inst_c0 = (guint32)data;
8859                                 else
8860                                         sp [-1]->inst_c0 = data;
8861 #else
8862                                 sp [-1]->inst_ls_word = data;
8863                                 if ((*ip) == CEE_CONV_U8)
8864                                         sp [-1]->inst_ms_word = 0;
8865                                 else
8866                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
8867 #endif
8868                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
8869                         }
8870                         else {
8871                                 ADD_UNOP (*ip);
8872                         }
8873                         ip++;
8874                         break;
8875                 case CEE_CONV_OVF_I4:
8876                 case CEE_CONV_OVF_I1:
8877                 case CEE_CONV_OVF_I2:
8878                 case CEE_CONV_OVF_I:
8879                 case CEE_CONV_OVF_U:
8880                         CHECK_STACK (1);
8881
8882                         if (sp [-1]->type == STACK_R8) {
8883                                 ADD_UNOP (CEE_CONV_OVF_I8);
8884                                 ADD_UNOP (*ip);
8885                         } else {
8886                                 ADD_UNOP (*ip);
8887                         }
8888                         ip++;
8889                         break;
8890                 case CEE_CONV_OVF_U1:
8891                 case CEE_CONV_OVF_U2:
8892                 case CEE_CONV_OVF_U4:
8893                         CHECK_STACK (1);
8894
8895                         if (sp [-1]->type == STACK_R8) {
8896                                 ADD_UNOP (CEE_CONV_OVF_U8);
8897                                 ADD_UNOP (*ip);
8898                         } else {
8899                                 ADD_UNOP (*ip);
8900                         }
8901                         ip++;
8902                         break;
8903                 case CEE_CONV_OVF_I1_UN:
8904                 case CEE_CONV_OVF_I2_UN:
8905                 case CEE_CONV_OVF_I4_UN:
8906                 case CEE_CONV_OVF_I8_UN:
8907                 case CEE_CONV_OVF_U1_UN:
8908                 case CEE_CONV_OVF_U2_UN:
8909                 case CEE_CONV_OVF_U4_UN:
8910                 case CEE_CONV_OVF_U8_UN:
8911                 case CEE_CONV_OVF_I_UN:
8912                 case CEE_CONV_OVF_U_UN:
8913                 case CEE_CONV_U2:
8914                 case CEE_CONV_U1:
8915                 case CEE_CONV_I:
8916                 case CEE_CONV_U:
8917                         CHECK_STACK (1);
8918                         ADD_UNOP (*ip);
8919                         CHECK_CFG_EXCEPTION;
8920                         ip++;
8921                         break;
8922                 case CEE_ADD_OVF:
8923                 case CEE_ADD_OVF_UN:
8924                 case CEE_MUL_OVF:
8925                 case CEE_MUL_OVF_UN:
8926                 case CEE_SUB_OVF:
8927                 case CEE_SUB_OVF_UN:
8928                         CHECK_STACK (2);
8929                         ADD_BINOP (*ip);
8930                         ip++;
8931                         break;
8932                 case CEE_CPOBJ:
8933                         GSHAREDVT_FAILURE (*ip);
8934                         CHECK_OPSIZE (5);
8935                         CHECK_STACK (2);
8936                         token = read32 (ip + 1);
8937                         klass = mini_get_class (method, token, generic_context);
8938                         CHECK_TYPELOAD (klass);
8939                         sp -= 2;
8940                         if (generic_class_is_reference_type (cfg, klass)) {
8941                                 MonoInst *store, *load;
8942                                 int dreg = alloc_ireg_ref (cfg);
8943
8944                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
8945                                 load->flags |= ins_flag;
8946                                 MONO_ADD_INS (cfg->cbb, load);
8947
8948                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
8949                                 store->flags |= ins_flag;
8950                                 MONO_ADD_INS (cfg->cbb, store);
8951
8952                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
8953                                         emit_write_barrier (cfg, sp [0], sp [1]);
8954                         } else {
8955                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
8956                         }
8957                         ins_flag = 0;
8958                         ip += 5;
8959                         break;
8960                 case CEE_LDOBJ: {
8961                         int loc_index = -1;
8962                         int stloc_len = 0;
8963
8964                         CHECK_OPSIZE (5);
8965                         CHECK_STACK (1);
8966                         --sp;
8967                         token = read32 (ip + 1);
8968                         klass = mini_get_class (method, token, generic_context);
8969                         CHECK_TYPELOAD (klass);
8970
8971                         /* Optimize the common ldobj+stloc combination */
8972                         switch (ip [5]) {
8973                         case CEE_STLOC_S:
8974                                 loc_index = ip [6];
8975                                 stloc_len = 2;
8976                                 break;
8977                         case CEE_STLOC_0:
8978                         case CEE_STLOC_1:
8979                         case CEE_STLOC_2:
8980                         case CEE_STLOC_3:
8981                                 loc_index = ip [5] - CEE_STLOC_0;
8982                                 stloc_len = 1;
8983                                 break;
8984                         default:
8985                                 break;
8986                         }
8987
8988                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
8989                                 CHECK_LOCAL (loc_index);
8990
8991                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
8992                                 ins->dreg = cfg->locals [loc_index]->dreg;
8993                                 ip += 5;
8994                                 ip += stloc_len;
8995                                 break;
8996                         }
8997
8998                         /* Optimize the ldobj+stobj combination */
8999                         /* The reference case ends up being a load+store anyway */
9000                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9001                                 CHECK_STACK (1);
9002
9003                                 sp --;
9004
9005                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9006
9007                                 ip += 5 + 5;
9008                                 ins_flag = 0;
9009                                 break;
9010                         }
9011
9012                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9013                         *sp++ = ins;
9014
9015                         ip += 5;
9016                         ins_flag = 0;
9017                         inline_costs += 1;
9018                         break;
9019                 }
9020                 case CEE_LDSTR:
9021                         CHECK_STACK_OVF (1);
9022                         CHECK_OPSIZE (5);
9023                         n = read32 (ip + 1);
9024
9025                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9026                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9027                                 ins->type = STACK_OBJ;
9028                                 *sp = ins;
9029                         }
9030                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9031                                 MonoInst *iargs [1];
9032
9033                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9034                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9035                         } else {
9036                                 if (cfg->opt & MONO_OPT_SHARED) {
9037                                         MonoInst *iargs [3];
9038
9039                                         if (cfg->compile_aot) {
9040                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9041                                         }
9042                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9043                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9044                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9045                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9046                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9047                                 } else {
9048                                         if (bblock->out_of_line) {
9049                                                 MonoInst *iargs [2];
9050
9051                                                 if (image == mono_defaults.corlib) {
9052                                                         /* 
9053                                                          * Avoid relocations in AOT and save some space by using a 
9054                                                          * version of helper_ldstr specialized to mscorlib.
9055                                                          */
9056                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9057                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9058                                                 } else {
9059                                                         /* Avoid creating the string object */
9060                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9061                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9062                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9063                                                 }
9064                                         } 
9065                                         else
9066                                         if (cfg->compile_aot) {
9067                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9068                                                 *sp = ins;
9069                                                 MONO_ADD_INS (bblock, ins);
9070                                         } 
9071                                         else {
9072                                                 NEW_PCONST (cfg, ins, NULL);
9073                                                 ins->type = STACK_OBJ;
9074                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9075                                                 if (!ins->inst_p0)
9076                                                         OUT_OF_MEMORY_FAILURE;
9077
9078                                                 *sp = ins;
9079                                                 MONO_ADD_INS (bblock, ins);
9080                                         }
9081                                 }
9082                         }
9083
9084                         sp++;
9085                         ip += 5;
9086                         break;
9087                 case CEE_NEWOBJ: {
9088                         MonoInst *iargs [2];
9089                         MonoMethodSignature *fsig;
9090                         MonoInst this_ins;
9091                         MonoInst *alloc;
9092                         MonoInst *vtable_arg = NULL;
9093
9094                         CHECK_OPSIZE (5);
9095                         token = read32 (ip + 1);
9096                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9097                         if (!cmethod || mono_loader_get_last_error ())
9098                                 LOAD_ERROR;
9099                         fsig = mono_method_get_signature (cmethod, image, token);
9100                         if (!fsig)
9101                                 LOAD_ERROR;
9102
9103                         mono_save_token_info (cfg, image, token, cmethod);
9104
9105                         if (!mono_class_init (cmethod->klass))
9106                                 TYPE_LOAD_ERROR (cmethod->klass);
9107
9108                         context_used = mini_method_check_context_used (cfg, cmethod);
9109
9110                         if (mono_security_cas_enabled ()) {
9111                                 if (check_linkdemand (cfg, method, cmethod))
9112                                         INLINE_FAILURE ("linkdemand");
9113                                 CHECK_CFG_EXCEPTION;
9114                         } else if (mono_security_core_clr_enabled ()) {
9115                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9116                         }
9117
9118                         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)) {
9119                                 emit_generic_class_init (cfg, cmethod->klass);
9120                                 CHECK_TYPELOAD (cmethod->klass);
9121                         }
9122
9123                         /*
9124                         if (cfg->gsharedvt) {
9125                                 if (mini_is_gsharedvt_variable_signature (sig))
9126                                         GSHAREDVT_FAILURE (*ip);
9127                         }
9128                         */
9129
9130                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9131                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9132                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9133                                         mono_class_vtable (cfg->domain, cmethod->klass);
9134                                         CHECK_TYPELOAD (cmethod->klass);
9135
9136                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9137                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9138                                 } else {
9139                                         if (context_used) {
9140                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9141                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9142                                         } else {
9143                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9144
9145                                                 CHECK_TYPELOAD (cmethod->klass);
9146                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9147                                         }
9148                                 }
9149                         }
9150
9151                         n = fsig->param_count;
9152                         CHECK_STACK (n);
9153
9154                         /* 
9155                          * Generate smaller code for the common newobj <exception> instruction in
9156                          * argument checking code.
9157                          */
9158                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9159                                 is_exception_class (cmethod->klass) && n <= 2 &&
9160                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9161                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9162                                 MonoInst *iargs [3];
9163
9164                                 g_assert (!vtable_arg);
9165
9166                                 sp -= n;
9167
9168                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9169                                 switch (n) {
9170                                 case 0:
9171                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9172                                         break;
9173                                 case 1:
9174                                         iargs [1] = sp [0];
9175                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9176                                         break;
9177                                 case 2:
9178                                         iargs [1] = sp [0];
9179                                         iargs [2] = sp [1];
9180                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9181                                         break;
9182                                 default:
9183                                         g_assert_not_reached ();
9184                                 }
9185
9186                                 ip += 5;
9187                                 inline_costs += 5;
9188                                 break;
9189                         }
9190
9191                         /* move the args to allow room for 'this' in the first position */
9192                         while (n--) {
9193                                 --sp;
9194                                 sp [1] = sp [0];
9195                         }
9196
9197                         /* check_call_signature () requires sp[0] to be set */
9198                         this_ins.type = STACK_OBJ;
9199                         sp [0] = &this_ins;
9200                         if (check_call_signature (cfg, fsig, sp))
9201                                 UNVERIFIED;
9202
9203                         iargs [0] = NULL;
9204
9205                         if (mini_class_is_system_array (cmethod->klass)) {
9206                                 g_assert (!vtable_arg);
9207
9208                                 *sp = emit_get_rgctx_method (cfg, context_used,
9209                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9210
9211                                 /* Avoid varargs in the common case */
9212                                 if (fsig->param_count == 1)
9213                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9214                                 else if (fsig->param_count == 2)
9215                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9216                                 else if (fsig->param_count == 3)
9217                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9218                                 else if (fsig->param_count == 4)
9219                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9220                                 else
9221                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9222                         } else if (cmethod->string_ctor) {
9223                                 g_assert (!context_used);
9224                                 g_assert (!vtable_arg);
9225                                 /* we simply pass a null pointer */
9226                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9227                                 /* now call the string ctor */
9228                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9229                         } else {
9230                                 MonoInst* callvirt_this_arg = NULL;
9231                                 
9232                                 if (cmethod->klass->valuetype) {
9233                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9234                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
9235                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9236
9237                                         alloc = NULL;
9238
9239                                         /* 
9240                                          * The code generated by mini_emit_virtual_call () expects
9241                                          * iargs [0] to be a boxed instance, but luckily the vcall
9242                                          * will be transformed into a normal call there.
9243                                          */
9244                                 } else if (context_used) {
9245                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9246                                         *sp = alloc;
9247                                 } else {
9248                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9249
9250                                         CHECK_TYPELOAD (cmethod->klass);
9251
9252                                         /*
9253                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9254                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9255                                          * As a workaround, we call class cctors before allocating objects.
9256                                          */
9257                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
9258                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
9259                                                 if (cfg->verbose_level > 2)
9260                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9261                                                 class_inits = g_slist_prepend (class_inits, vtable);
9262                                         }
9263
9264                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9265                                         *sp = alloc;
9266                                 }
9267                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9268
9269                                 if (alloc)
9270                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9271
9272                                 /* Now call the actual ctor */
9273                                 /* Avoid virtual calls to ctors if possible */
9274                                 if (mono_class_is_marshalbyref (cmethod->klass))
9275                                         callvirt_this_arg = sp [0];
9276
9277
9278                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9279                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9280                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9281                                                 *sp = ins;
9282                                                 sp++;
9283                                         }
9284
9285                                         CHECK_CFG_EXCEPTION;
9286                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9287                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9288                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9289                                     !g_list_find (dont_inline, cmethod)) {
9290                                         int costs;
9291
9292                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9293                                                 cfg->real_offset += 5;
9294                                                 bblock = cfg->cbb;
9295
9296                                                 inline_costs += costs - 5;
9297                                         } else {
9298                                                 INLINE_FAILURE ("inline failure");
9299                                                 // FIXME-VT: Clean this up
9300                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9301                                                         GSHAREDVT_FAILURE(*ip);
9302                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9303                                         }
9304                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9305                                         MonoInst *addr;
9306
9307                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9308                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9309                                 } else if (context_used &&
9310                                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
9311                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
9312                                         MonoInst *cmethod_addr;
9313
9314                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9315                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9316
9317                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9318                                 } else {
9319                                         INLINE_FAILURE ("ctor call");
9320                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9321                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9322                                 }
9323                         }
9324
9325                         if (alloc == NULL) {
9326                                 /* Valuetype */
9327                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9328                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9329                                 *sp++= ins;
9330                         }
9331                         else
9332                                 *sp++ = alloc;
9333                         
9334                         ip += 5;
9335                         inline_costs += 5;
9336                         break;
9337                 }
9338                 case CEE_CASTCLASS:
9339                         CHECK_STACK (1);
9340                         --sp;
9341                         CHECK_OPSIZE (5);
9342                         token = read32 (ip + 1);
9343                         klass = mini_get_class (method, token, generic_context);
9344                         CHECK_TYPELOAD (klass);
9345                         if (sp [0]->type != STACK_OBJ)
9346                                 UNVERIFIED;
9347
9348                         context_used = mini_class_check_context_used (cfg, klass);
9349
9350                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9351                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9352                                 MonoInst *args [3];
9353
9354                                 /* obj */
9355                                 args [0] = *sp;
9356
9357                                 /* klass */
9358                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9359
9360                                 /* inline cache*/
9361                                 if (cfg->compile_aot)
9362                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9363                                 else
9364                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9365
9366                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9367                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9368                                 ip += 5;
9369                                 inline_costs += 2;
9370                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9371                                 MonoMethod *mono_castclass;
9372                                 MonoInst *iargs [1];
9373                                 int costs;
9374
9375                                 mono_castclass = mono_marshal_get_castclass (klass); 
9376                                 iargs [0] = sp [0];
9377                                 
9378                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9379                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9380                                 CHECK_CFG_EXCEPTION;
9381                                 g_assert (costs > 0);
9382                                 
9383                                 ip += 5;
9384                                 cfg->real_offset += 5;
9385                                 bblock = cfg->cbb;
9386
9387                                 *sp++ = iargs [0];
9388
9389                                 inline_costs += costs;
9390                         }
9391                         else {
9392                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9393                                 CHECK_CFG_EXCEPTION;
9394                                 bblock = cfg->cbb;
9395                                 *sp ++ = ins;
9396                                 ip += 5;
9397                         }
9398                         break;
9399                 case CEE_ISINST: {
9400                         CHECK_STACK (1);
9401                         --sp;
9402                         CHECK_OPSIZE (5);
9403                         token = read32 (ip + 1);
9404                         klass = mini_get_class (method, token, generic_context);
9405                         CHECK_TYPELOAD (klass);
9406                         if (sp [0]->type != STACK_OBJ)
9407                                 UNVERIFIED;
9408  
9409                         context_used = mini_class_check_context_used (cfg, klass);
9410
9411                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9412                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9413                                 MonoInst *args [3];
9414
9415                                 /* obj */
9416                                 args [0] = *sp;
9417
9418                                 /* klass */
9419                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9420
9421                                 /* inline cache*/
9422                                 if (cfg->compile_aot)
9423                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9424                                 else
9425                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9426
9427                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9428                                 ip += 5;
9429                                 inline_costs += 2;
9430                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9431                                 MonoMethod *mono_isinst;
9432                                 MonoInst *iargs [1];
9433                                 int costs;
9434
9435                                 mono_isinst = mono_marshal_get_isinst (klass); 
9436                                 iargs [0] = sp [0];
9437
9438                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9439                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9440                                 CHECK_CFG_EXCEPTION;
9441                                 g_assert (costs > 0);
9442                                 
9443                                 ip += 5;
9444                                 cfg->real_offset += 5;
9445                                 bblock = cfg->cbb;
9446
9447                                 *sp++= iargs [0];
9448
9449                                 inline_costs += costs;
9450                         }
9451                         else {
9452                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9453                                 CHECK_CFG_EXCEPTION;
9454                                 bblock = cfg->cbb;
9455                                 *sp ++ = ins;
9456                                 ip += 5;
9457                         }
9458                         break;
9459                 }
9460                 case CEE_UNBOX_ANY: {
9461                         CHECK_STACK (1);
9462                         --sp;
9463                         CHECK_OPSIZE (5);
9464                         token = read32 (ip + 1);
9465                         klass = mini_get_class (method, token, generic_context);
9466                         CHECK_TYPELOAD (klass);
9467  
9468                         mono_save_token_info (cfg, image, token, klass);
9469
9470                         context_used = mini_class_check_context_used (cfg, klass);
9471
9472                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9473                                 *sp = handle_unbox_gsharedvt (cfg, context_used, klass, *sp, &bblock);
9474                                 sp ++;
9475
9476                                 ip += 5;
9477                                 inline_costs += 2;
9478                                 break;
9479                         }
9480
9481                         if (generic_class_is_reference_type (cfg, klass)) {
9482                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9483                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9484                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9485                                         MonoInst *args [3];
9486
9487                                         /* obj */
9488                                         args [0] = *sp;
9489
9490                                         /* klass */
9491                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9492
9493                                         /* inline cache*/
9494                                         /*FIXME AOT support*/
9495                                         if (cfg->compile_aot)
9496                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9497                                         else
9498                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9499
9500                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9501                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9502                                         ip += 5;
9503                                         inline_costs += 2;
9504                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9505                                         MonoMethod *mono_castclass;
9506                                         MonoInst *iargs [1];
9507                                         int costs;
9508
9509                                         mono_castclass = mono_marshal_get_castclass (klass); 
9510                                         iargs [0] = sp [0];
9511
9512                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9513                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9514                                         CHECK_CFG_EXCEPTION;
9515                                         g_assert (costs > 0);
9516                                 
9517                                         ip += 5;
9518                                         cfg->real_offset += 5;
9519                                         bblock = cfg->cbb;
9520
9521                                         *sp++ = iargs [0];
9522                                         inline_costs += costs;
9523                                 } else {
9524                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9525                                         CHECK_CFG_EXCEPTION;
9526                                         bblock = cfg->cbb;
9527                                         *sp ++ = ins;
9528                                         ip += 5;
9529                                 }
9530                                 break;
9531                         }
9532
9533                         if (mono_class_is_nullable (klass)) {
9534                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9535                                 *sp++= ins;
9536                                 ip += 5;
9537                                 break;
9538                         }
9539
9540                         /* UNBOX */
9541                         ins = handle_unbox (cfg, klass, sp, context_used);
9542                         *sp = ins;
9543
9544                         ip += 5;
9545
9546                         /* LDOBJ */
9547                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9548                         *sp++ = ins;
9549
9550                         inline_costs += 2;
9551                         break;
9552                 }
9553                 case CEE_BOX: {
9554                         MonoInst *val;
9555
9556                         CHECK_STACK (1);
9557                         --sp;
9558                         val = *sp;
9559                         CHECK_OPSIZE (5);
9560                         token = read32 (ip + 1);
9561                         klass = mini_get_class (method, token, generic_context);
9562                         CHECK_TYPELOAD (klass);
9563
9564                         mono_save_token_info (cfg, image, token, klass);
9565
9566                         context_used = mini_class_check_context_used (cfg, klass);
9567
9568                         if (generic_class_is_reference_type (cfg, klass)) {
9569                                 *sp++ = val;
9570                                 ip += 5;
9571                                 break;
9572                         }
9573
9574                         if (klass == mono_defaults.void_class)
9575                                 UNVERIFIED;
9576                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9577                                 UNVERIFIED;
9578                         /* frequent check in generic code: box (struct), brtrue */
9579
9580                         // FIXME: LLVM can't handle the inconsistent bb linking
9581                         if (!mono_class_is_nullable (klass) &&
9582                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9583                                 (ip [5] == CEE_BRTRUE || 
9584                                  ip [5] == CEE_BRTRUE_S ||
9585                                  ip [5] == CEE_BRFALSE ||
9586                                  ip [5] == CEE_BRFALSE_S)) {
9587                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9588                                 int dreg;
9589                                 MonoBasicBlock *true_bb, *false_bb;
9590
9591                                 ip += 5;
9592
9593                                 if (cfg->verbose_level > 3) {
9594                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9595                                         printf ("<box+brtrue opt>\n");
9596                                 }
9597
9598                                 switch (*ip) {
9599                                 case CEE_BRTRUE_S:
9600                                 case CEE_BRFALSE_S:
9601                                         CHECK_OPSIZE (2);
9602                                         ip++;
9603                                         target = ip + 1 + (signed char)(*ip);
9604                                         ip++;
9605                                         break;
9606                                 case CEE_BRTRUE:
9607                                 case CEE_BRFALSE:
9608                                         CHECK_OPSIZE (5);
9609                                         ip++;
9610                                         target = ip + 4 + (gint)(read32 (ip));
9611                                         ip += 4;
9612                                         break;
9613                                 default:
9614                                         g_assert_not_reached ();
9615                                 }
9616
9617                                 /* 
9618                                  * We need to link both bblocks, since it is needed for handling stack
9619                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9620                                  * Branching to only one of them would lead to inconsistencies, so
9621                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9622                                  */
9623                                 GET_BBLOCK (cfg, true_bb, target);
9624                                 GET_BBLOCK (cfg, false_bb, ip);
9625
9626                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9627                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9628
9629                                 if (sp != stack_start) {
9630                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9631                                         sp = stack_start;
9632                                         CHECK_UNVERIFIABLE (cfg);
9633                                 }
9634
9635                                 if (COMPILE_LLVM (cfg)) {
9636                                         dreg = alloc_ireg (cfg);
9637                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9638                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9639
9640                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9641                                 } else {
9642                                         /* The JIT can't eliminate the iconst+compare */
9643                                         MONO_INST_NEW (cfg, ins, OP_BR);
9644                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9645                                         MONO_ADD_INS (cfg->cbb, ins);
9646                                 }
9647
9648                                 start_new_bblock = 1;
9649                                 break;
9650                         }
9651
9652                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9653
9654                         CHECK_CFG_EXCEPTION;
9655                         ip += 5;
9656                         inline_costs += 1;
9657                         break;
9658                 }
9659                 case CEE_UNBOX: {
9660                         CHECK_STACK (1);
9661                         --sp;
9662                         CHECK_OPSIZE (5);
9663                         token = read32 (ip + 1);
9664                         klass = mini_get_class (method, token, generic_context);
9665                         CHECK_TYPELOAD (klass);
9666
9667                         mono_save_token_info (cfg, image, token, klass);
9668
9669                         context_used = mini_class_check_context_used (cfg, klass);
9670
9671                         if (mono_class_is_nullable (klass)) {
9672                                 MonoInst *val;
9673
9674                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9675                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9676
9677                                 *sp++= ins;
9678                         } else {
9679                                 ins = handle_unbox (cfg, klass, sp, context_used);
9680                                 *sp++ = ins;
9681                         }
9682                         ip += 5;
9683                         inline_costs += 2;
9684                         break;
9685                 }
9686                 case CEE_LDFLD:
9687                 case CEE_LDFLDA:
9688                 case CEE_STFLD:
9689                 case CEE_LDSFLD:
9690                 case CEE_LDSFLDA:
9691                 case CEE_STSFLD: {
9692                         MonoClassField *field;
9693 #ifndef DISABLE_REMOTING
9694                         int costs;
9695 #endif
9696                         guint foffset;
9697                         gboolean is_instance;
9698                         int op;
9699                         gpointer addr = NULL;
9700                         gboolean is_special_static;
9701                         MonoType *ftype;
9702                         MonoInst *store_val = NULL;
9703
9704                         op = *ip;
9705                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
9706                         if (is_instance) {
9707                                 if (op == CEE_STFLD) {
9708                                         CHECK_STACK (2);
9709                                         sp -= 2;
9710                                         store_val = sp [1];
9711                                 } else {
9712                                         CHECK_STACK (1);
9713                                         --sp;
9714                                 }
9715                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
9716                                         UNVERIFIED;
9717                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
9718                                         UNVERIFIED;
9719                         } else {
9720                                 if (op == CEE_STSFLD) {
9721                                         CHECK_STACK (1);
9722                                         sp--;
9723                                         store_val = sp [0];
9724                                 }
9725                         }
9726
9727                         CHECK_OPSIZE (5);
9728                         token = read32 (ip + 1);
9729                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
9730                                 field = mono_method_get_wrapper_data (method, token);
9731                                 klass = field->parent;
9732                         }
9733                         else {
9734                                 field = mono_field_from_token (image, token, &klass, generic_context);
9735                         }
9736                         if (!field)
9737                                 LOAD_ERROR;
9738                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
9739                                 FIELD_ACCESS_FAILURE;
9740                         mono_class_init (klass);
9741
9742                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
9743                                 UNVERIFIED;
9744
9745                         /* if the class is Critical then transparent code cannot access it's fields */
9746                         if (!is_instance && mono_security_core_clr_enabled ())
9747                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9748
9749                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
9750                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
9751                         if (mono_security_core_clr_enabled ())
9752                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9753                         */
9754
9755                         /*
9756                          * LDFLD etc. is usable on static fields as well, so convert those cases to
9757                          * the static case.
9758                          */
9759                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9760                                 switch (op) {
9761                                 case CEE_LDFLD:
9762                                         op = CEE_LDSFLD;
9763                                         break;
9764                                 case CEE_STFLD:
9765                                         op = CEE_STSFLD;
9766                                         break;
9767                                 case CEE_LDFLDA:
9768                                         op = CEE_LDSFLDA;
9769                                         break;
9770                                 default:
9771                                         g_assert_not_reached ();
9772                                 }
9773                                 is_instance = FALSE;
9774                         }
9775
9776                         context_used = mini_class_check_context_used (cfg, klass);
9777
9778                         /* INSTANCE CASE */
9779
9780                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
9781                         if (op == CEE_STFLD) {
9782                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
9783                                         UNVERIFIED;
9784 #ifndef DISABLE_REMOTING
9785                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
9786                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
9787                                         MonoInst *iargs [5];
9788
9789                                         GSHAREDVT_FAILURE (op);
9790
9791                                         iargs [0] = sp [0];
9792                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9793                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9794                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
9795                                                     field->offset);
9796                                         iargs [4] = sp [1];
9797
9798                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9799                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
9800                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
9801                                                 CHECK_CFG_EXCEPTION;
9802                                                 g_assert (costs > 0);
9803                                                       
9804                                                 cfg->real_offset += 5;
9805                                                 bblock = cfg->cbb;
9806
9807                                                 inline_costs += costs;
9808                                         } else {
9809                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
9810                                         }
9811                                 } else
9812 #endif
9813                                 {
9814                                         MonoInst *store;
9815
9816                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9817
9818                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9819                                                 MonoInst *offset_ins;
9820
9821                                                 context_used = mini_class_check_context_used (cfg, klass);
9822
9823                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9824                                                 dreg = alloc_ireg_mp (cfg);
9825                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9826                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
9827                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
9828                                         } else {
9829                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
9830                                         }
9831                                         if (sp [0]->opcode != OP_LDADDR)
9832                                                 store->flags |= MONO_INST_FAULT;
9833
9834                                 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)) {
9835                                         /* insert call to write barrier */
9836                                         MonoInst *ptr;
9837                                         int dreg;
9838
9839                                         dreg = alloc_ireg_mp (cfg);
9840                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
9841                                         emit_write_barrier (cfg, ptr, sp [1]);
9842                                 }
9843
9844                                         store->flags |= ins_flag;
9845                                 }
9846                                 ins_flag = 0;
9847                                 ip += 5;
9848                                 break;
9849                         }
9850
9851 #ifndef DISABLE_REMOTING
9852                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
9853                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
9854                                 MonoInst *iargs [4];
9855
9856                                 GSHAREDVT_FAILURE (op);
9857
9858                                 iargs [0] = sp [0];
9859                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9860                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9861                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
9862                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9863                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
9864                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9865                                         CHECK_CFG_EXCEPTION;
9866                                         bblock = cfg->cbb;
9867                                         g_assert (costs > 0);
9868                                                       
9869                                         cfg->real_offset += 5;
9870
9871                                         *sp++ = iargs [0];
9872
9873                                         inline_costs += costs;
9874                                 } else {
9875                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
9876                                         *sp++ = ins;
9877                                 }
9878                         } else 
9879 #endif
9880                         if (is_instance) {
9881                                 if (sp [0]->type == STACK_VTYPE) {
9882                                         MonoInst *var;
9883
9884                                         /* Have to compute the address of the variable */
9885
9886                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
9887                                         if (!var)
9888                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
9889                                         else
9890                                                 g_assert (var->klass == klass);
9891                                         
9892                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
9893                                         sp [0] = ins;
9894                                 }
9895
9896                                 if (op == CEE_LDFLDA) {
9897                                         if (is_magic_tls_access (field)) {
9898                                                 GSHAREDVT_FAILURE (*ip);
9899                                                 ins = sp [0];
9900                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
9901                                         } else {
9902                                                 if (sp [0]->type == STACK_OBJ) {
9903                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
9904                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
9905                                                 }
9906
9907                                                 dreg = alloc_ireg_mp (cfg);
9908
9909                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
9910                                                         MonoInst *offset_ins;
9911
9912                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9913                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9914                                                 } else {
9915                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
9916                                                 }
9917                                                 ins->klass = mono_class_from_mono_type (field->type);
9918                                                 ins->type = STACK_MP;
9919                                                 *sp++ = ins;
9920                                         }
9921                                 } else {
9922                                         MonoInst *load;
9923
9924                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9925
9926                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9927                                                 MonoInst *offset_ins;
9928
9929                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9930                                                 dreg = alloc_ireg_mp (cfg);
9931                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9932                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
9933                                         } else {
9934                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
9935                                         }
9936                                         load->flags |= ins_flag;
9937                                         if (sp [0]->opcode != OP_LDADDR)
9938                                                 load->flags |= MONO_INST_FAULT;
9939                                         *sp++ = load;
9940                                 }
9941                         }
9942
9943                         if (is_instance) {
9944                                 ins_flag = 0;
9945                                 ip += 5;
9946                                 break;
9947                         }
9948
9949                         /* STATIC CASE */
9950
9951                         /*
9952                          * We can only support shared generic static
9953                          * field access on architectures where the
9954                          * trampoline code has been extended to handle
9955                          * the generic class init.
9956                          */
9957 #ifndef MONO_ARCH_VTABLE_REG
9958                         GENERIC_SHARING_FAILURE (op);
9959 #endif
9960
9961                         context_used = mini_class_check_context_used (cfg, klass);
9962
9963                         ftype = mono_field_get_type (field);
9964
9965                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
9966                                 UNVERIFIED;
9967
9968                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
9969                          * to be called here.
9970                          */
9971                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
9972                                 mono_class_vtable (cfg->domain, klass);
9973                                 CHECK_TYPELOAD (klass);
9974                         }
9975                         mono_domain_lock (cfg->domain);
9976                         if (cfg->domain->special_static_fields)
9977                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
9978                         mono_domain_unlock (cfg->domain);
9979
9980                         is_special_static = mono_class_field_is_special_static (field);
9981
9982                         /* Generate IR to compute the field address */
9983                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
9984                                 /*
9985                                  * Fast access to TLS data
9986                                  * Inline version of get_thread_static_data () in
9987                                  * threads.c.
9988                                  */
9989                                 guint32 offset;
9990                                 int idx, static_data_reg, array_reg, dreg;
9991                                 MonoInst *thread_ins;
9992
9993                                 GSHAREDVT_FAILURE (op);
9994
9995                                 // offset &= 0x7fffffff;
9996                                 // idx = (offset >> 24) - 1;
9997                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
9998
9999                                 thread_ins = mono_get_thread_intrinsic (cfg);
10000                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10001                                 static_data_reg = alloc_ireg (cfg);
10002                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10003
10004                                 if (cfg->compile_aot) {
10005                                         int offset_reg, offset2_reg, idx_reg;
10006
10007                                         /* For TLS variables, this will return the TLS offset */
10008                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10009                                         offset_reg = ins->dreg;
10010                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10011                                         idx_reg = alloc_ireg (cfg);
10012                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10013                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10014                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10015                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10016                                         array_reg = alloc_ireg (cfg);
10017                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10018                                         offset2_reg = alloc_ireg (cfg);
10019                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10020                                         dreg = alloc_ireg (cfg);
10021                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10022                                 } else {
10023                                         offset = (gsize)addr & 0x7fffffff;
10024                                         idx = (offset >> 24) - 1;
10025
10026                                         array_reg = alloc_ireg (cfg);
10027                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10028                                         dreg = alloc_ireg (cfg);
10029                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10030                                 }
10031                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10032                                         (cfg->compile_aot && is_special_static) ||
10033                                         (context_used && is_special_static)) {
10034                                 MonoInst *iargs [2];
10035
10036                                 g_assert (field->parent);
10037                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10038                                 if (context_used) {
10039                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10040                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10041                                 } else {
10042                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10043                                 }
10044                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10045                         } else if (context_used) {
10046                                 MonoInst *static_data;
10047
10048                                 /*
10049                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10050                                         method->klass->name_space, method->klass->name, method->name,
10051                                         depth, field->offset);
10052                                 */
10053
10054                                 if (mono_class_needs_cctor_run (klass, method))
10055                                         emit_generic_class_init (cfg, klass);
10056
10057                                 /*
10058                                  * The pointer we're computing here is
10059                                  *
10060                                  *   super_info.static_data + field->offset
10061                                  */
10062                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10063                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10064
10065                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10066                                         MonoInst *offset_ins;
10067
10068                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10069                                         dreg = alloc_ireg_mp (cfg);
10070                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10071                                 } else if (field->offset == 0) {
10072                                         ins = static_data;
10073                                 } else {
10074                                         int addr_reg = mono_alloc_preg (cfg);
10075                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10076                                 }
10077                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10078                                 MonoInst *iargs [2];
10079
10080                                 g_assert (field->parent);
10081                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10082                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10083                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10084                         } else {
10085                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
10086
10087                                 CHECK_TYPELOAD (klass);
10088                                 if (!addr) {
10089                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable)) {
10090                                                 if (!(g_slist_find (class_inits, vtable))) {
10091                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
10092                                                         if (cfg->verbose_level > 2)
10093                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10094                                                         class_inits = g_slist_prepend (class_inits, vtable);
10095                                                 }
10096                                         } else {
10097                                                 if (cfg->run_cctors) {
10098                                                         MonoException *ex;
10099                                                         /* This makes so that inline cannot trigger */
10100                                                         /* .cctors: too many apps depend on them */
10101                                                         /* running with a specific order... */
10102                                                         if (! vtable->initialized)
10103                                                                 INLINE_FAILURE ("class init");
10104                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10105                                                         if (ex) {
10106                                                                 set_exception_object (cfg, ex);
10107                                                                 goto exception_exit;
10108                                                         }
10109                                                 }
10110                                         }
10111                                         addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10112
10113                                         if (cfg->compile_aot)
10114                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10115                                         else
10116                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10117                                 } else {
10118                                         MonoInst *iargs [1];
10119                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10120                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10121                                 }
10122                         }
10123
10124                         /* Generate IR to do the actual load/store operation */
10125
10126                         if (op == CEE_LDSFLDA) {
10127                                 ins->klass = mono_class_from_mono_type (ftype);
10128                                 ins->type = STACK_PTR;
10129                                 *sp++ = ins;
10130                         } else if (op == CEE_STSFLD) {
10131                                 MonoInst *store;
10132
10133                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10134                                 store->flags |= ins_flag;
10135                         } else {
10136                                 gboolean is_const = FALSE;
10137                                 MonoVTable *vtable = NULL;
10138                                 gpointer addr = NULL;
10139
10140                                 if (!context_used) {
10141                                         vtable = mono_class_vtable (cfg->domain, klass);
10142                                         CHECK_TYPELOAD (klass);
10143                                 }
10144                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10145                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10146                                         int ro_type = ftype->type;
10147                                         if (!addr)
10148                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10149                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10150                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10151                                         }
10152
10153                                         GSHAREDVT_FAILURE (op);
10154
10155                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10156                                         is_const = TRUE;
10157                                         switch (ro_type) {
10158                                         case MONO_TYPE_BOOLEAN:
10159                                         case MONO_TYPE_U1:
10160                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10161                                                 sp++;
10162                                                 break;
10163                                         case MONO_TYPE_I1:
10164                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10165                                                 sp++;
10166                                                 break;                                          
10167                                         case MONO_TYPE_CHAR:
10168                                         case MONO_TYPE_U2:
10169                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10170                                                 sp++;
10171                                                 break;
10172                                         case MONO_TYPE_I2:
10173                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10174                                                 sp++;
10175                                                 break;
10176                                                 break;
10177                                         case MONO_TYPE_I4:
10178                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10179                                                 sp++;
10180                                                 break;                                          
10181                                         case MONO_TYPE_U4:
10182                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10183                                                 sp++;
10184                                                 break;
10185                                         case MONO_TYPE_I:
10186                                         case MONO_TYPE_U:
10187                                         case MONO_TYPE_PTR:
10188                                         case MONO_TYPE_FNPTR:
10189                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10190                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10191                                                 sp++;
10192                                                 break;
10193                                         case MONO_TYPE_STRING:
10194                                         case MONO_TYPE_OBJECT:
10195                                         case MONO_TYPE_CLASS:
10196                                         case MONO_TYPE_SZARRAY:
10197                                         case MONO_TYPE_ARRAY:
10198                                                 if (!mono_gc_is_moving ()) {
10199                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10200                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10201                                                         sp++;
10202                                                 } else {
10203                                                         is_const = FALSE;
10204                                                 }
10205                                                 break;
10206                                         case MONO_TYPE_I8:
10207                                         case MONO_TYPE_U8:
10208                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10209                                                 sp++;
10210                                                 break;
10211                                         case MONO_TYPE_R4:
10212                                         case MONO_TYPE_R8:
10213                                         case MONO_TYPE_VALUETYPE:
10214                                         default:
10215                                                 is_const = FALSE;
10216                                                 break;
10217                                         }
10218                                 }
10219
10220                                 if (!is_const) {
10221                                         MonoInst *load;
10222
10223                                         CHECK_STACK_OVF (1);
10224
10225                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10226                                         load->flags |= ins_flag;
10227                                         ins_flag = 0;
10228                                         *sp++ = load;
10229                                 }
10230                         }
10231                         ins_flag = 0;
10232                         ip += 5;
10233                         break;
10234                 }
10235                 case CEE_STOBJ:
10236                         CHECK_STACK (2);
10237                         sp -= 2;
10238                         CHECK_OPSIZE (5);
10239                         token = read32 (ip + 1);
10240                         klass = mini_get_class (method, token, generic_context);
10241                         CHECK_TYPELOAD (klass);
10242                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10243                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10244                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10245                                         generic_class_is_reference_type (cfg, klass)) {
10246                                 /* insert call to write barrier */
10247                                 emit_write_barrier (cfg, sp [0], sp [1]);
10248                         }
10249                         ins_flag = 0;
10250                         ip += 5;
10251                         inline_costs += 1;
10252                         break;
10253
10254                         /*
10255                          * Array opcodes
10256                          */
10257                 case CEE_NEWARR: {
10258                         MonoInst *len_ins;
10259                         const char *data_ptr;
10260                         int data_size = 0;
10261                         guint32 field_token;
10262
10263                         CHECK_STACK (1);
10264                         --sp;
10265
10266                         CHECK_OPSIZE (5);
10267                         token = read32 (ip + 1);
10268
10269                         klass = mini_get_class (method, token, generic_context);
10270                         CHECK_TYPELOAD (klass);
10271
10272                         context_used = mini_class_check_context_used (cfg, klass);
10273
10274                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10275                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
10276                                 ins->sreg1 = sp [0]->dreg;
10277                                 ins->type = STACK_I4;
10278                                 ins->dreg = alloc_ireg (cfg);
10279                                 MONO_ADD_INS (cfg->cbb, ins);
10280                                 *sp = mono_decompose_opcode (cfg, ins);
10281                         }
10282
10283                         if (context_used) {
10284                                 MonoInst *args [3];
10285                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10286                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10287
10288                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10289
10290                                 /* vtable */
10291                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10292                                         array_class, MONO_RGCTX_INFO_VTABLE);
10293                                 /* array len */
10294                                 args [1] = sp [0];
10295
10296                                 if (managed_alloc)
10297                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10298                                 else
10299                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10300                         } else {
10301                                 if (cfg->opt & MONO_OPT_SHARED) {
10302                                         /* Decompose now to avoid problems with references to the domainvar */
10303                                         MonoInst *iargs [3];
10304
10305                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10306                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10307                                         iargs [2] = sp [0];
10308
10309                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10310                                 } else {
10311                                         /* Decompose later since it is needed by abcrem */
10312                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10313                                         mono_class_vtable (cfg->domain, array_type);
10314                                         CHECK_TYPELOAD (array_type);
10315
10316                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10317                                         ins->dreg = alloc_ireg_ref (cfg);
10318                                         ins->sreg1 = sp [0]->dreg;
10319                                         ins->inst_newa_class = klass;
10320                                         ins->type = STACK_OBJ;
10321                                         ins->klass = array_type;
10322                                         MONO_ADD_INS (cfg->cbb, ins);
10323                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10324                                         cfg->cbb->has_array_access = TRUE;
10325
10326                                         /* Needed so mono_emit_load_get_addr () gets called */
10327                                         mono_get_got_var (cfg);
10328                                 }
10329                         }
10330
10331                         len_ins = sp [0];
10332                         ip += 5;
10333                         *sp++ = ins;
10334                         inline_costs += 1;
10335
10336                         /* 
10337                          * we inline/optimize the initialization sequence if possible.
10338                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10339                          * for small sizes open code the memcpy
10340                          * ensure the rva field is big enough
10341                          */
10342                         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))) {
10343                                 MonoMethod *memcpy_method = get_memcpy_method ();
10344                                 MonoInst *iargs [3];
10345                                 int add_reg = alloc_ireg_mp (cfg);
10346
10347                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10348                                 if (cfg->compile_aot) {
10349                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10350                                 } else {
10351                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10352                                 }
10353                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10354                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10355                                 ip += 11;
10356                         }
10357
10358                         break;
10359                 }
10360                 case CEE_LDLEN:
10361                         CHECK_STACK (1);
10362                         --sp;
10363                         if (sp [0]->type != STACK_OBJ)
10364                                 UNVERIFIED;
10365
10366                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10367                         ins->dreg = alloc_preg (cfg);
10368                         ins->sreg1 = sp [0]->dreg;
10369                         ins->type = STACK_I4;
10370                         /* This flag will be inherited by the decomposition */
10371                         ins->flags |= MONO_INST_FAULT;
10372                         MONO_ADD_INS (cfg->cbb, ins);
10373                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10374                         cfg->cbb->has_array_access = TRUE;
10375                         ip ++;
10376                         *sp++ = ins;
10377                         break;
10378                 case CEE_LDELEMA:
10379                         CHECK_STACK (2);
10380                         sp -= 2;
10381                         CHECK_OPSIZE (5);
10382                         if (sp [0]->type != STACK_OBJ)
10383                                 UNVERIFIED;
10384
10385                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10386
10387                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10388                         CHECK_TYPELOAD (klass);
10389                         /* we need to make sure that this array is exactly the type it needs
10390                          * to be for correctness. the wrappers are lax with their usage
10391                          * so we need to ignore them here
10392                          */
10393                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10394                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10395                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10396                                 CHECK_TYPELOAD (array_class);
10397                         }
10398
10399                         readonly = FALSE;
10400                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10401                         *sp++ = ins;
10402                         ip += 5;
10403                         break;
10404                 case CEE_LDELEM:
10405                 case CEE_LDELEM_I1:
10406                 case CEE_LDELEM_U1:
10407                 case CEE_LDELEM_I2:
10408                 case CEE_LDELEM_U2:
10409                 case CEE_LDELEM_I4:
10410                 case CEE_LDELEM_U4:
10411                 case CEE_LDELEM_I8:
10412                 case CEE_LDELEM_I:
10413                 case CEE_LDELEM_R4:
10414                 case CEE_LDELEM_R8:
10415                 case CEE_LDELEM_REF: {
10416                         MonoInst *addr;
10417
10418                         CHECK_STACK (2);
10419                         sp -= 2;
10420
10421                         if (*ip == CEE_LDELEM) {
10422                                 CHECK_OPSIZE (5);
10423                                 token = read32 (ip + 1);
10424                                 klass = mini_get_class (method, token, generic_context);
10425                                 CHECK_TYPELOAD (klass);
10426                                 mono_class_init (klass);
10427                         }
10428                         else
10429                                 klass = array_access_to_klass (*ip);
10430
10431                         if (sp [0]->type != STACK_OBJ)
10432                                 UNVERIFIED;
10433
10434                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10435
10436                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10437                                 // FIXME-VT: OP_ICONST optimization
10438                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10439                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10440                                 ins->opcode = OP_LOADV_MEMBASE;
10441                         } else if (sp [1]->opcode == OP_ICONST) {
10442                                 int array_reg = sp [0]->dreg;
10443                                 int index_reg = sp [1]->dreg;
10444                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10445
10446                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10447                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10448                         } else {
10449                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10450                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10451                         }
10452                         *sp++ = ins;
10453                         if (*ip == CEE_LDELEM)
10454                                 ip += 5;
10455                         else
10456                                 ++ip;
10457                         break;
10458                 }
10459                 case CEE_STELEM_I:
10460                 case CEE_STELEM_I1:
10461                 case CEE_STELEM_I2:
10462                 case CEE_STELEM_I4:
10463                 case CEE_STELEM_I8:
10464                 case CEE_STELEM_R4:
10465                 case CEE_STELEM_R8:
10466                 case CEE_STELEM_REF:
10467                 case CEE_STELEM: {
10468                         CHECK_STACK (3);
10469                         sp -= 3;
10470
10471                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10472
10473                         if (*ip == CEE_STELEM) {
10474                                 CHECK_OPSIZE (5);
10475                                 token = read32 (ip + 1);
10476                                 klass = mini_get_class (method, token, generic_context);
10477                                 CHECK_TYPELOAD (klass);
10478                                 mono_class_init (klass);
10479                         }
10480                         else
10481                                 klass = array_access_to_klass (*ip);
10482
10483                         if (sp [0]->type != STACK_OBJ)
10484                                 UNVERIFIED;
10485
10486                         emit_array_store (cfg, klass, sp, TRUE);
10487
10488                         if (*ip == CEE_STELEM)
10489                                 ip += 5;
10490                         else
10491                                 ++ip;
10492                         inline_costs += 1;
10493                         break;
10494                 }
10495                 case CEE_CKFINITE: {
10496                         CHECK_STACK (1);
10497                         --sp;
10498
10499                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10500                         ins->sreg1 = sp [0]->dreg;
10501                         ins->dreg = alloc_freg (cfg);
10502                         ins->type = STACK_R8;
10503                         MONO_ADD_INS (bblock, ins);
10504
10505                         *sp++ = mono_decompose_opcode (cfg, ins);
10506
10507                         ++ip;
10508                         break;
10509                 }
10510                 case CEE_REFANYVAL: {
10511                         MonoInst *src_var, *src;
10512
10513                         int klass_reg = alloc_preg (cfg);
10514                         int dreg = alloc_preg (cfg);
10515
10516                         GSHAREDVT_FAILURE (*ip);
10517
10518                         CHECK_STACK (1);
10519                         MONO_INST_NEW (cfg, ins, *ip);
10520                         --sp;
10521                         CHECK_OPSIZE (5);
10522                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10523                         CHECK_TYPELOAD (klass);
10524                         mono_class_init (klass);
10525
10526                         context_used = mini_class_check_context_used (cfg, klass);
10527
10528                         // FIXME:
10529                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10530                         if (!src_var)
10531                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10532                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10533                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10534
10535                         if (context_used) {
10536                                 MonoInst *klass_ins;
10537
10538                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10539                                                 klass, MONO_RGCTX_INFO_KLASS);
10540
10541                                 // FIXME:
10542                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10543                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10544                         } else {
10545                                 mini_emit_class_check (cfg, klass_reg, klass);
10546                         }
10547                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10548                         ins->type = STACK_MP;
10549                         *sp++ = ins;
10550                         ip += 5;
10551                         break;
10552                 }
10553                 case CEE_MKREFANY: {
10554                         MonoInst *loc, *addr;
10555
10556                         GSHAREDVT_FAILURE (*ip);
10557
10558                         CHECK_STACK (1);
10559                         MONO_INST_NEW (cfg, ins, *ip);
10560                         --sp;
10561                         CHECK_OPSIZE (5);
10562                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10563                         CHECK_TYPELOAD (klass);
10564                         mono_class_init (klass);
10565
10566                         context_used = mini_class_check_context_used (cfg, klass);
10567
10568                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10569                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10570
10571                         if (context_used) {
10572                                 MonoInst *const_ins;
10573                                 int type_reg = alloc_preg (cfg);
10574
10575                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10576                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10577                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10578                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10579                         } else if (cfg->compile_aot) {
10580                                 int const_reg = alloc_preg (cfg);
10581                                 int type_reg = alloc_preg (cfg);
10582
10583                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10584                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10585                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10586                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10587                         } else {
10588                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10589                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10590                         }
10591                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10592
10593                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10594                         ins->type = STACK_VTYPE;
10595                         ins->klass = mono_defaults.typed_reference_class;
10596                         *sp++ = ins;
10597                         ip += 5;
10598                         break;
10599                 }
10600                 case CEE_LDTOKEN: {
10601                         gpointer handle;
10602                         MonoClass *handle_class;
10603
10604                         CHECK_STACK_OVF (1);
10605
10606                         CHECK_OPSIZE (5);
10607                         n = read32 (ip + 1);
10608
10609                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10610                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10611                                 handle = mono_method_get_wrapper_data (method, n);
10612                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10613                                 if (handle_class == mono_defaults.typehandle_class)
10614                                         handle = &((MonoClass*)handle)->byval_arg;
10615                         }
10616                         else {
10617                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10618                         }
10619                         if (!handle)
10620                                 LOAD_ERROR;
10621                         mono_class_init (handle_class);
10622                         if (cfg->generic_sharing_context) {
10623                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10624                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10625                                         /* This case handles ldtoken
10626                                            of an open type, like for
10627                                            typeof(Gen<>). */
10628                                         context_used = 0;
10629                                 } else if (handle_class == mono_defaults.typehandle_class) {
10630                                         /* If we get a MONO_TYPE_CLASS
10631                                            then we need to provide the
10632                                            open type, not an
10633                                            instantiation of it. */
10634                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10635                                                 context_used = 0;
10636                                         else
10637                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10638                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10639                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10640                                 else if (handle_class == mono_defaults.methodhandle_class)
10641                                         context_used = mini_method_check_context_used (cfg, handle);
10642                                 else
10643                                         g_assert_not_reached ();
10644                         }
10645
10646                         if ((cfg->opt & MONO_OPT_SHARED) &&
10647                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10648                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10649                                 MonoInst *addr, *vtvar, *iargs [3];
10650                                 int method_context_used;
10651
10652                                 method_context_used = mini_method_check_context_used (cfg, method);
10653
10654                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10655
10656                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10657                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10658                                 if (method_context_used) {
10659                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10660                                                 method, MONO_RGCTX_INFO_METHOD);
10661                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10662                                 } else {
10663                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10664                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10665                                 }
10666                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10667
10668                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10669
10670                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10671                         } else {
10672                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10673                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10674                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10675                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
10676                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10677                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10678
10679                                         mono_class_init (tclass);
10680                                         if (context_used) {
10681                                                 ins = emit_get_rgctx_klass (cfg, context_used,
10682                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
10683                                         } else if (cfg->compile_aot) {
10684                                                 if (method->wrapper_type) {
10685                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
10686                                                                 /* Special case for static synchronized wrappers */
10687                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
10688                                                         } else {
10689                                                                 /* FIXME: n is not a normal token */
10690                                                                 cfg->disable_aot = TRUE;
10691                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
10692                                                         }
10693                                                 } else {
10694                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
10695                                                 }
10696                                         } else {
10697                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
10698                                         }
10699                                         ins->type = STACK_OBJ;
10700                                         ins->klass = cmethod->klass;
10701                                         ip += 5;
10702                                 } else {
10703                                         MonoInst *addr, *vtvar;
10704
10705                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
10706
10707                                         if (context_used) {
10708                                                 if (handle_class == mono_defaults.typehandle_class) {
10709                                                         ins = emit_get_rgctx_klass (cfg, context_used,
10710                                                                         mono_class_from_mono_type (handle),
10711                                                                         MONO_RGCTX_INFO_TYPE);
10712                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
10713                                                         ins = emit_get_rgctx_method (cfg, context_used,
10714                                                                         handle, MONO_RGCTX_INFO_METHOD);
10715                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
10716                                                         ins = emit_get_rgctx_field (cfg, context_used,
10717                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
10718                                                 } else {
10719                                                         g_assert_not_reached ();
10720                                                 }
10721                                         } else if (cfg->compile_aot) {
10722                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
10723                                         } else {
10724                                                 EMIT_NEW_PCONST (cfg, ins, handle);
10725                                         }
10726                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10727                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10728                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10729                                 }
10730                         }
10731
10732                         *sp++ = ins;
10733                         ip += 5;
10734                         break;
10735                 }
10736                 case CEE_THROW:
10737                         CHECK_STACK (1);
10738                         MONO_INST_NEW (cfg, ins, OP_THROW);
10739                         --sp;
10740                         ins->sreg1 = sp [0]->dreg;
10741                         ip++;
10742                         bblock->out_of_line = TRUE;
10743                         MONO_ADD_INS (bblock, ins);
10744                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10745                         MONO_ADD_INS (bblock, ins);
10746                         sp = stack_start;
10747                         
10748                         link_bblock (cfg, bblock, end_bblock);
10749                         start_new_bblock = 1;
10750                         break;
10751                 case CEE_ENDFINALLY:
10752                         /* mono_save_seq_point_info () depends on this */
10753                         if (sp != stack_start)
10754                                 emit_seq_point (cfg, method, ip, FALSE);
10755                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
10756                         MONO_ADD_INS (bblock, ins);
10757                         ip++;
10758                         start_new_bblock = 1;
10759
10760                         /*
10761                          * Control will leave the method so empty the stack, otherwise
10762                          * the next basic block will start with a nonempty stack.
10763                          */
10764                         while (sp != stack_start) {
10765                                 sp--;
10766                         }
10767                         break;
10768                 case CEE_LEAVE:
10769                 case CEE_LEAVE_S: {
10770                         GList *handlers;
10771
10772                         if (*ip == CEE_LEAVE) {
10773                                 CHECK_OPSIZE (5);
10774                                 target = ip + 5 + (gint32)read32(ip + 1);
10775                         } else {
10776                                 CHECK_OPSIZE (2);
10777                                 target = ip + 2 + (signed char)(ip [1]);
10778                         }
10779
10780                         /* empty the stack */
10781                         while (sp != stack_start) {
10782                                 sp--;
10783                         }
10784
10785                         /* 
10786                          * If this leave statement is in a catch block, check for a
10787                          * pending exception, and rethrow it if necessary.
10788                          * We avoid doing this in runtime invoke wrappers, since those are called
10789                          * by native code which excepts the wrapper to catch all exceptions.
10790                          */
10791                         for (i = 0; i < header->num_clauses; ++i) {
10792                                 MonoExceptionClause *clause = &header->clauses [i];
10793
10794                                 /* 
10795                                  * Use <= in the final comparison to handle clauses with multiple
10796                                  * leave statements, like in bug #78024.
10797                                  * The ordering of the exception clauses guarantees that we find the
10798                                  * innermost clause.
10799                                  */
10800                                 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) {
10801                                         MonoInst *exc_ins;
10802                                         MonoBasicBlock *dont_throw;
10803
10804                                         /*
10805                                           MonoInst *load;
10806
10807                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
10808                                         */
10809
10810                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
10811
10812                                         NEW_BBLOCK (cfg, dont_throw);
10813
10814                                         /*
10815                                          * Currently, we always rethrow the abort exception, despite the 
10816                                          * fact that this is not correct. See thread6.cs for an example. 
10817                                          * But propagating the abort exception is more important than 
10818                                          * getting the sematics right.
10819                                          */
10820                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
10821                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
10822                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
10823
10824                                         MONO_START_BB (cfg, dont_throw);
10825                                         bblock = cfg->cbb;
10826                                 }
10827                         }
10828
10829                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
10830                                 GList *tmp;
10831                                 MonoExceptionClause *clause;
10832
10833                                 for (tmp = handlers; tmp; tmp = tmp->next) {
10834                                         clause = tmp->data;
10835                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
10836                                         g_assert (tblock);
10837                                         link_bblock (cfg, bblock, tblock);
10838                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
10839                                         ins->inst_target_bb = tblock;
10840                                         ins->inst_eh_block = clause;
10841                                         MONO_ADD_INS (bblock, ins);
10842                                         bblock->has_call_handler = 1;
10843                                         if (COMPILE_LLVM (cfg)) {
10844                                                 MonoBasicBlock *target_bb;
10845
10846                                                 /* 
10847                                                  * Link the finally bblock with the target, since it will
10848                                                  * conceptually branch there.
10849                                                  * FIXME: Have to link the bblock containing the endfinally.
10850                                                  */
10851                                                 GET_BBLOCK (cfg, target_bb, target);
10852                                                 link_bblock (cfg, tblock, target_bb);
10853                                         }
10854                                 }
10855                                 g_list_free (handlers);
10856                         } 
10857
10858                         MONO_INST_NEW (cfg, ins, OP_BR);
10859                         MONO_ADD_INS (bblock, ins);
10860                         GET_BBLOCK (cfg, tblock, target);
10861                         link_bblock (cfg, bblock, tblock);
10862                         ins->inst_target_bb = tblock;
10863                         start_new_bblock = 1;
10864
10865                         if (*ip == CEE_LEAVE)
10866                                 ip += 5;
10867                         else
10868                                 ip += 2;
10869
10870                         break;
10871                 }
10872
10873                         /*
10874                          * Mono specific opcodes
10875                          */
10876                 case MONO_CUSTOM_PREFIX: {
10877
10878                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
10879
10880                         CHECK_OPSIZE (2);
10881                         switch (ip [1]) {
10882                         case CEE_MONO_ICALL: {
10883                                 gpointer func;
10884                                 MonoJitICallInfo *info;
10885
10886                                 token = read32 (ip + 2);
10887                                 func = mono_method_get_wrapper_data (method, token);
10888                                 info = mono_find_jit_icall_by_addr (func);
10889                                 if (!info)
10890                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
10891                                 g_assert (info);
10892
10893                                 CHECK_STACK (info->sig->param_count);
10894                                 sp -= info->sig->param_count;
10895
10896                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
10897                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
10898                                         *sp++ = ins;
10899
10900                                 ip += 6;
10901                                 inline_costs += 10 * num_calls++;
10902
10903                                 break;
10904                         }
10905                         case CEE_MONO_LDPTR: {
10906                                 gpointer ptr;
10907
10908                                 CHECK_STACK_OVF (1);
10909                                 CHECK_OPSIZE (6);
10910                                 token = read32 (ip + 2);
10911
10912                                 ptr = mono_method_get_wrapper_data (method, token);
10913                                 /* FIXME: Generalize this */
10914                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
10915                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
10916                                         *sp++ = ins;
10917                                         ip += 6;
10918                                         break;
10919                                 }
10920                                 EMIT_NEW_PCONST (cfg, ins, ptr);
10921                                 *sp++ = ins;
10922                                 ip += 6;
10923                                 inline_costs += 10 * num_calls++;
10924                                 /* Can't embed random pointers into AOT code */
10925                                 cfg->disable_aot = 1;
10926                                 break;
10927                         }
10928                         case CEE_MONO_JIT_ICALL_ADDR: {
10929                                 MonoJitICallInfo *callinfo;
10930                                 gpointer ptr;
10931
10932                                 CHECK_STACK_OVF (1);
10933                                 CHECK_OPSIZE (6);
10934                                 token = read32 (ip + 2);
10935
10936                                 ptr = mono_method_get_wrapper_data (method, token);
10937                                 callinfo = mono_find_jit_icall_by_addr (ptr);
10938                                 g_assert (callinfo);
10939                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
10940                                 *sp++ = ins;
10941                                 ip += 6;
10942                                 inline_costs += 10 * num_calls++;
10943                                 break;
10944                         }
10945                         case CEE_MONO_ICALL_ADDR: {
10946                                 MonoMethod *cmethod;
10947                                 gpointer ptr;
10948
10949                                 CHECK_STACK_OVF (1);
10950                                 CHECK_OPSIZE (6);
10951                                 token = read32 (ip + 2);
10952
10953                                 cmethod = mono_method_get_wrapper_data (method, token);
10954
10955                                 if (cfg->compile_aot) {
10956                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
10957                                 } else {
10958                                         ptr = mono_lookup_internal_call (cmethod);
10959                                         g_assert (ptr);
10960                                         EMIT_NEW_PCONST (cfg, ins, ptr);
10961                                 }
10962                                 *sp++ = ins;
10963                                 ip += 6;
10964                                 break;
10965                         }
10966                         case CEE_MONO_VTADDR: {
10967                                 MonoInst *src_var, *src;
10968
10969                                 CHECK_STACK (1);
10970                                 --sp;
10971
10972                                 // FIXME:
10973                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10974                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
10975                                 *sp++ = src;
10976                                 ip += 2;
10977                                 break;
10978                         }
10979                         case CEE_MONO_NEWOBJ: {
10980                                 MonoInst *iargs [2];
10981
10982                                 CHECK_STACK_OVF (1);
10983                                 CHECK_OPSIZE (6);
10984                                 token = read32 (ip + 2);
10985                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
10986                                 mono_class_init (klass);
10987                                 NEW_DOMAINCONST (cfg, iargs [0]);
10988                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
10989                                 NEW_CLASSCONST (cfg, iargs [1], klass);
10990                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
10991                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
10992                                 ip += 6;
10993                                 inline_costs += 10 * num_calls++;
10994                                 break;
10995                         }
10996                         case CEE_MONO_OBJADDR:
10997                                 CHECK_STACK (1);
10998                                 --sp;
10999                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11000                                 ins->dreg = alloc_ireg_mp (cfg);
11001                                 ins->sreg1 = sp [0]->dreg;
11002                                 ins->type = STACK_MP;
11003                                 MONO_ADD_INS (cfg->cbb, ins);
11004                                 *sp++ = ins;
11005                                 ip += 2;
11006                                 break;
11007                         case CEE_MONO_LDNATIVEOBJ:
11008                                 /*
11009                                  * Similar to LDOBJ, but instead load the unmanaged 
11010                                  * representation of the vtype to the stack.
11011                                  */
11012                                 CHECK_STACK (1);
11013                                 CHECK_OPSIZE (6);
11014                                 --sp;
11015                                 token = read32 (ip + 2);
11016                                 klass = mono_method_get_wrapper_data (method, token);
11017                                 g_assert (klass->valuetype);
11018                                 mono_class_init (klass);
11019
11020                                 {
11021                                         MonoInst *src, *dest, *temp;
11022
11023                                         src = sp [0];
11024                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11025                                         temp->backend.is_pinvoke = 1;
11026                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11027                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11028
11029                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11030                                         dest->type = STACK_VTYPE;
11031                                         dest->klass = klass;
11032
11033                                         *sp ++ = dest;
11034                                         ip += 6;
11035                                 }
11036                                 break;
11037                         case CEE_MONO_RETOBJ: {
11038                                 /*
11039                                  * Same as RET, but return the native representation of a vtype
11040                                  * to the caller.
11041                                  */
11042                                 g_assert (cfg->ret);
11043                                 g_assert (mono_method_signature (method)->pinvoke); 
11044                                 CHECK_STACK (1);
11045                                 --sp;
11046                                 
11047                                 CHECK_OPSIZE (6);
11048                                 token = read32 (ip + 2);    
11049                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11050
11051                                 if (!cfg->vret_addr) {
11052                                         g_assert (cfg->ret_var_is_local);
11053
11054                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11055                                 } else {
11056                                         EMIT_NEW_RETLOADA (cfg, ins);
11057                                 }
11058                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11059                                 
11060                                 if (sp != stack_start)
11061                                         UNVERIFIED;
11062                                 
11063                                 MONO_INST_NEW (cfg, ins, OP_BR);
11064                                 ins->inst_target_bb = end_bblock;
11065                                 MONO_ADD_INS (bblock, ins);
11066                                 link_bblock (cfg, bblock, end_bblock);
11067                                 start_new_bblock = 1;
11068                                 ip += 6;
11069                                 break;
11070                         }
11071                         case CEE_MONO_CISINST:
11072                         case CEE_MONO_CCASTCLASS: {
11073                                 int token;
11074                                 CHECK_STACK (1);
11075                                 --sp;
11076                                 CHECK_OPSIZE (6);
11077                                 token = read32 (ip + 2);
11078                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11079                                 if (ip [1] == CEE_MONO_CISINST)
11080                                         ins = handle_cisinst (cfg, klass, sp [0]);
11081                                 else
11082                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11083                                 bblock = cfg->cbb;
11084                                 *sp++ = ins;
11085                                 ip += 6;
11086                                 break;
11087                         }
11088                         case CEE_MONO_SAVE_LMF:
11089                         case CEE_MONO_RESTORE_LMF:
11090 #ifdef MONO_ARCH_HAVE_LMF_OPS
11091                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11092                                 MONO_ADD_INS (bblock, ins);
11093                                 cfg->need_lmf_area = TRUE;
11094 #endif
11095                                 ip += 2;
11096                                 break;
11097                         case CEE_MONO_CLASSCONST:
11098                                 CHECK_STACK_OVF (1);
11099                                 CHECK_OPSIZE (6);
11100                                 token = read32 (ip + 2);
11101                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11102                                 *sp++ = ins;
11103                                 ip += 6;
11104                                 inline_costs += 10 * num_calls++;
11105                                 break;
11106                         case CEE_MONO_NOT_TAKEN:
11107                                 bblock->out_of_line = TRUE;
11108                                 ip += 2;
11109                                 break;
11110                         case CEE_MONO_TLS:
11111                                 CHECK_STACK_OVF (1);
11112                                 CHECK_OPSIZE (6);
11113                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11114                                 ins->dreg = alloc_preg (cfg);
11115                                 ins->inst_offset = (gint32)read32 (ip + 2);
11116                                 ins->type = STACK_PTR;
11117                                 MONO_ADD_INS (bblock, ins);
11118                                 *sp++ = ins;
11119                                 ip += 6;
11120                                 break;
11121                         case CEE_MONO_DYN_CALL: {
11122                                 MonoCallInst *call;
11123
11124                                 /* It would be easier to call a trampoline, but that would put an
11125                                  * extra frame on the stack, confusing exception handling. So
11126                                  * implement it inline using an opcode for now.
11127                                  */
11128
11129                                 if (!cfg->dyn_call_var) {
11130                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11131                                         /* prevent it from being register allocated */
11132                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
11133                                 }
11134
11135                                 /* Has to use a call inst since it local regalloc expects it */
11136                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11137                                 ins = (MonoInst*)call;
11138                                 sp -= 2;
11139                                 ins->sreg1 = sp [0]->dreg;
11140                                 ins->sreg2 = sp [1]->dreg;
11141                                 MONO_ADD_INS (bblock, ins);
11142
11143 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
11144                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11145 #endif
11146
11147                                 ip += 2;
11148                                 inline_costs += 10 * num_calls++;
11149
11150                                 break;
11151                         }
11152                         case CEE_MONO_MEMORY_BARRIER: {
11153                                 CHECK_OPSIZE (5);
11154                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11155                                 ip += 5;
11156                                 break;
11157                         }
11158                         case CEE_MONO_JIT_ATTACH: {
11159                                 MonoInst *args [16];
11160                                 MonoInst *ad_ins, *lmf_ins;
11161                                 MonoBasicBlock *next_bb = NULL;
11162
11163                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11164
11165                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11166                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11167
11168 #if TARGET_WIN32
11169                                 ad_ins = NULL;
11170                                 lmf_ins = NULL;
11171 #else
11172                                 ad_ins = mono_get_domain_intrinsic (cfg);
11173                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11174 #endif
11175
11176                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11177                                         NEW_BBLOCK (cfg, next_bb);
11178
11179                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11180                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11181                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11182
11183                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11184                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11185                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11186                                 }
11187
11188                                 if (cfg->compile_aot) {
11189                                         /* AOT code is only used in the root domain */
11190                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11191                                 } else {
11192                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11193                                 }
11194                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11195                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11196
11197                                 if (next_bb) {
11198                                         MONO_START_BB (cfg, next_bb);
11199                                         bblock = cfg->cbb;
11200                                 }
11201                                 ip += 2;
11202                                 break;
11203                         }
11204                         case CEE_MONO_JIT_DETACH: {
11205                                 MonoInst *args [16];
11206
11207                                 /* Restore the original domain */
11208                                 dreg = alloc_ireg (cfg);
11209                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11210                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11211                                 ip += 2;
11212                                 break;
11213                         }
11214                         default:
11215                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11216                                 break;
11217                         }
11218                         break;
11219                 }
11220
11221                 case CEE_PREFIX1: {
11222                         CHECK_OPSIZE (2);
11223                         switch (ip [1]) {
11224                         case CEE_ARGLIST: {
11225                                 /* somewhat similar to LDTOKEN */
11226                                 MonoInst *addr, *vtvar;
11227                                 CHECK_STACK_OVF (1);
11228                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11229
11230                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11231                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11232
11233                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11234                                 ins->type = STACK_VTYPE;
11235                                 ins->klass = mono_defaults.argumenthandle_class;
11236                                 *sp++ = ins;
11237                                 ip += 2;
11238                                 break;
11239                         }
11240                         case CEE_CEQ:
11241                         case CEE_CGT:
11242                         case CEE_CGT_UN:
11243                         case CEE_CLT:
11244                         case CEE_CLT_UN: {
11245                                 MonoInst *cmp;
11246                                 CHECK_STACK (2);
11247                                 /*
11248                                  * The following transforms:
11249                                  *    CEE_CEQ    into OP_CEQ
11250                                  *    CEE_CGT    into OP_CGT
11251                                  *    CEE_CGT_UN into OP_CGT_UN
11252                                  *    CEE_CLT    into OP_CLT
11253                                  *    CEE_CLT_UN into OP_CLT_UN
11254                                  */
11255                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11256                                 
11257                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11258                                 sp -= 2;
11259                                 cmp->sreg1 = sp [0]->dreg;
11260                                 cmp->sreg2 = sp [1]->dreg;
11261                                 type_from_op (cmp, sp [0], sp [1]);
11262                                 CHECK_TYPE (cmp);
11263                                 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))))
11264                                         cmp->opcode = OP_LCOMPARE;
11265                                 else if (sp [0]->type == STACK_R8)
11266                                         cmp->opcode = OP_FCOMPARE;
11267                                 else
11268                                         cmp->opcode = OP_ICOMPARE;
11269                                 MONO_ADD_INS (bblock, cmp);
11270                                 ins->type = STACK_I4;
11271                                 ins->dreg = alloc_dreg (cfg, ins->type);
11272                                 type_from_op (ins, sp [0], sp [1]);
11273
11274                                 if (cmp->opcode == OP_FCOMPARE) {
11275                                         /*
11276                                          * The backends expect the fceq opcodes to do the
11277                                          * comparison too.
11278                                          */
11279                                         cmp->opcode = OP_NOP;
11280                                         ins->sreg1 = cmp->sreg1;
11281                                         ins->sreg2 = cmp->sreg2;
11282                                 }
11283                                 MONO_ADD_INS (bblock, ins);
11284                                 *sp++ = ins;
11285                                 ip += 2;
11286                                 break;
11287                         }
11288                         case CEE_LDFTN: {
11289                                 MonoInst *argconst;
11290                                 MonoMethod *cil_method;
11291
11292                                 CHECK_STACK_OVF (1);
11293                                 CHECK_OPSIZE (6);
11294                                 n = read32 (ip + 2);
11295                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11296                                 if (!cmethod || mono_loader_get_last_error ())
11297                                         LOAD_ERROR;
11298                                 mono_class_init (cmethod->klass);
11299
11300                                 mono_save_token_info (cfg, image, n, cmethod);
11301
11302                                 context_used = mini_method_check_context_used (cfg, cmethod);
11303
11304                                 cil_method = cmethod;
11305                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11306                                         METHOD_ACCESS_FAILURE;
11307
11308                                 if (mono_security_cas_enabled ()) {
11309                                         if (check_linkdemand (cfg, method, cmethod))
11310                                                 INLINE_FAILURE ("linkdemand");
11311                                         CHECK_CFG_EXCEPTION;
11312                                 } else if (mono_security_core_clr_enabled ()) {
11313                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11314                                 }
11315
11316                                 /* 
11317                                  * Optimize the common case of ldftn+delegate creation
11318                                  */
11319                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11320                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11321                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11322                                                 MonoInst *target_ins;
11323                                                 MonoMethod *invoke;
11324                                                 int invoke_context_used;
11325
11326                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11327                                                 if (!invoke || !mono_method_signature (invoke))
11328                                                         LOAD_ERROR;
11329
11330                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11331
11332                                                 target_ins = sp [-1];
11333
11334                                                 if (mono_security_core_clr_enabled ())
11335                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11336
11337                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11338                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11339                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11340                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11341                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11342                                                         }
11343                                                 }
11344
11345 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11346                                                 /* FIXME: SGEN support */
11347                                                 if (invoke_context_used == 0) {
11348                                                         ip += 6;
11349                                                         if (cfg->verbose_level > 3)
11350                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11351                                                         sp --;
11352                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11353                                                         CHECK_CFG_EXCEPTION;
11354                                                         ip += 5;                        
11355                                                         sp ++;
11356                                                         break;
11357                                                 }
11358 #endif
11359                                         }
11360                                 }
11361
11362                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11363                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11364                                 *sp++ = ins;
11365                                 
11366                                 ip += 6;
11367                                 inline_costs += 10 * num_calls++;
11368                                 break;
11369                         }
11370                         case CEE_LDVIRTFTN: {
11371                                 MonoInst *args [2];
11372
11373                                 CHECK_STACK (1);
11374                                 CHECK_OPSIZE (6);
11375                                 n = read32 (ip + 2);
11376                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11377                                 if (!cmethod || mono_loader_get_last_error ())
11378                                         LOAD_ERROR;
11379                                 mono_class_init (cmethod->klass);
11380  
11381                                 context_used = mini_method_check_context_used (cfg, cmethod);
11382
11383                                 if (mono_security_cas_enabled ()) {
11384                                         if (check_linkdemand (cfg, method, cmethod))
11385                                                 INLINE_FAILURE ("linkdemand");
11386                                         CHECK_CFG_EXCEPTION;
11387                                 } else if (mono_security_core_clr_enabled ()) {
11388                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11389                                 }
11390
11391                                 --sp;
11392                                 args [0] = *sp;
11393
11394                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11395                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11396
11397                                 if (context_used)
11398                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11399                                 else
11400                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11401
11402                                 ip += 6;
11403                                 inline_costs += 10 * num_calls++;
11404                                 break;
11405                         }
11406                         case CEE_LDARG:
11407                                 CHECK_STACK_OVF (1);
11408                                 CHECK_OPSIZE (4);
11409                                 n = read16 (ip + 2);
11410                                 CHECK_ARG (n);
11411                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11412                                 *sp++ = ins;
11413                                 ip += 4;
11414                                 break;
11415                         case CEE_LDARGA:
11416                                 CHECK_STACK_OVF (1);
11417                                 CHECK_OPSIZE (4);
11418                                 n = read16 (ip + 2);
11419                                 CHECK_ARG (n);
11420                                 NEW_ARGLOADA (cfg, ins, n);
11421                                 MONO_ADD_INS (cfg->cbb, ins);
11422                                 *sp++ = ins;
11423                                 ip += 4;
11424                                 break;
11425                         case CEE_STARG:
11426                                 CHECK_STACK (1);
11427                                 --sp;
11428                                 CHECK_OPSIZE (4);
11429                                 n = read16 (ip + 2);
11430                                 CHECK_ARG (n);
11431                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11432                                         UNVERIFIED;
11433                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11434                                 ip += 4;
11435                                 break;
11436                         case CEE_LDLOC:
11437                                 CHECK_STACK_OVF (1);
11438                                 CHECK_OPSIZE (4);
11439                                 n = read16 (ip + 2);
11440                                 CHECK_LOCAL (n);
11441                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11442                                 *sp++ = ins;
11443                                 ip += 4;
11444                                 break;
11445                         case CEE_LDLOCA: {
11446                                 unsigned char *tmp_ip;
11447                                 CHECK_STACK_OVF (1);
11448                                 CHECK_OPSIZE (4);
11449                                 n = read16 (ip + 2);
11450                                 CHECK_LOCAL (n);
11451
11452                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11453                                         ip = tmp_ip;
11454                                         inline_costs += 1;
11455                                         break;
11456                                 }                       
11457                                 
11458                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11459                                 *sp++ = ins;
11460                                 ip += 4;
11461                                 break;
11462                         }
11463                         case CEE_STLOC:
11464                                 CHECK_STACK (1);
11465                                 --sp;
11466                                 CHECK_OPSIZE (4);
11467                                 n = read16 (ip + 2);
11468                                 CHECK_LOCAL (n);
11469                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11470                                         UNVERIFIED;
11471                                 emit_stloc_ir (cfg, sp, header, n);
11472                                 ip += 4;
11473                                 inline_costs += 1;
11474                                 break;
11475                         case CEE_LOCALLOC:
11476                                 CHECK_STACK (1);
11477                                 --sp;
11478                                 if (sp != stack_start) 
11479                                         UNVERIFIED;
11480                                 if (cfg->method != method) 
11481                                         /* 
11482                                          * Inlining this into a loop in a parent could lead to 
11483                                          * stack overflows which is different behavior than the
11484                                          * non-inlined case, thus disable inlining in this case.
11485                                          */
11486                                         goto inline_failure;
11487
11488                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11489                                 ins->dreg = alloc_preg (cfg);
11490                                 ins->sreg1 = sp [0]->dreg;
11491                                 ins->type = STACK_PTR;
11492                                 MONO_ADD_INS (cfg->cbb, ins);
11493
11494                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11495                                 if (init_locals)
11496                                         ins->flags |= MONO_INST_INIT;
11497
11498                                 *sp++ = ins;
11499                                 ip += 2;
11500                                 break;
11501                         case CEE_ENDFILTER: {
11502                                 MonoExceptionClause *clause, *nearest;
11503                                 int cc, nearest_num;
11504
11505                                 CHECK_STACK (1);
11506                                 --sp;
11507                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11508                                         UNVERIFIED;
11509                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11510                                 ins->sreg1 = (*sp)->dreg;
11511                                 MONO_ADD_INS (bblock, ins);
11512                                 start_new_bblock = 1;
11513                                 ip += 2;
11514
11515                                 nearest = NULL;
11516                                 nearest_num = 0;
11517                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11518                                         clause = &header->clauses [cc];
11519                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11520                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11521                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11522                                                 nearest = clause;
11523                                                 nearest_num = cc;
11524                                         }
11525                                 }
11526                                 g_assert (nearest);
11527                                 if ((ip - header->code) != nearest->handler_offset)
11528                                         UNVERIFIED;
11529
11530                                 break;
11531                         }
11532                         case CEE_UNALIGNED_:
11533                                 ins_flag |= MONO_INST_UNALIGNED;
11534                                 /* FIXME: record alignment? we can assume 1 for now */
11535                                 CHECK_OPSIZE (3);
11536                                 ip += 3;
11537                                 break;
11538                         case CEE_VOLATILE_:
11539                                 ins_flag |= MONO_INST_VOLATILE;
11540                                 ip += 2;
11541                                 break;
11542                         case CEE_TAIL_:
11543                                 ins_flag   |= MONO_INST_TAILCALL;
11544                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11545                                 /* Can't inline tail calls at this time */
11546                                 inline_costs += 100000;
11547                                 ip += 2;
11548                                 break;
11549                         case CEE_INITOBJ:
11550                                 CHECK_STACK (1);
11551                                 --sp;
11552                                 CHECK_OPSIZE (6);
11553                                 token = read32 (ip + 2);
11554                                 klass = mini_get_class (method, token, generic_context);
11555                                 CHECK_TYPELOAD (klass);
11556                                 if (generic_class_is_reference_type (cfg, klass))
11557                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11558                                 else
11559                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11560                                 ip += 6;
11561                                 inline_costs += 1;
11562                                 break;
11563                         case CEE_CONSTRAINED_:
11564                                 CHECK_OPSIZE (6);
11565                                 token = read32 (ip + 2);
11566                                 constrained_call = mini_get_class (method, token, generic_context);
11567                                 CHECK_TYPELOAD (constrained_call);
11568                                 ip += 6;
11569                                 break;
11570                         case CEE_CPBLK:
11571                         case CEE_INITBLK: {
11572                                 MonoInst *iargs [3];
11573                                 CHECK_STACK (3);
11574                                 sp -= 3;
11575
11576                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11577                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11578                                 } 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)) {
11579                                         /* emit_memset only works when val == 0 */
11580                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11581                                 } else {
11582                                         iargs [0] = sp [0];
11583                                         iargs [1] = sp [1];
11584                                         iargs [2] = sp [2];
11585                                         if (ip [1] == CEE_CPBLK) {
11586                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11587                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11588                                         } else {
11589                                                 MonoMethod *memset_method = get_memset_method ();
11590                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11591                                         }
11592                                 }
11593                                 ip += 2;
11594                                 inline_costs += 1;
11595                                 break;
11596                         }
11597                         case CEE_NO_:
11598                                 CHECK_OPSIZE (3);
11599                                 if (ip [2] & 0x1)
11600                                         ins_flag |= MONO_INST_NOTYPECHECK;
11601                                 if (ip [2] & 0x2)
11602                                         ins_flag |= MONO_INST_NORANGECHECK;
11603                                 /* we ignore the no-nullcheck for now since we
11604                                  * really do it explicitly only when doing callvirt->call
11605                                  */
11606                                 ip += 3;
11607                                 break;
11608                         case CEE_RETHROW: {
11609                                 MonoInst *load;
11610                                 int handler_offset = -1;
11611
11612                                 for (i = 0; i < header->num_clauses; ++i) {
11613                                         MonoExceptionClause *clause = &header->clauses [i];
11614                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11615                                                 handler_offset = clause->handler_offset;
11616                                                 break;
11617                                         }
11618                                 }
11619
11620                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11621
11622                                 g_assert (handler_offset != -1);
11623
11624                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11625                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11626                                 ins->sreg1 = load->dreg;
11627                                 MONO_ADD_INS (bblock, ins);
11628
11629                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11630                                 MONO_ADD_INS (bblock, ins);
11631
11632                                 sp = stack_start;
11633                                 link_bblock (cfg, bblock, end_bblock);
11634                                 start_new_bblock = 1;
11635                                 ip += 2;
11636                                 break;
11637                         }
11638                         case CEE_SIZEOF: {
11639                                 guint32 val;
11640                                 int ialign;
11641
11642                                 GSHAREDVT_FAILURE (*ip);
11643
11644                                 CHECK_STACK_OVF (1);
11645                                 CHECK_OPSIZE (6);
11646                                 token = read32 (ip + 2);
11647                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11648                                         MonoType *type = mono_type_create_from_typespec (image, token);
11649                                         val = mono_type_size (type, &ialign);
11650                                 } else {
11651                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11652                                         CHECK_TYPELOAD (klass);
11653                                         mono_class_init (klass);
11654                                         val = mono_type_size (&klass->byval_arg, &ialign);
11655                                 }
11656                                 EMIT_NEW_ICONST (cfg, ins, val);
11657                                 *sp++= ins;
11658                                 ip += 6;
11659                                 break;
11660                         }
11661                         case CEE_REFANYTYPE: {
11662                                 MonoInst *src_var, *src;
11663
11664                                 GSHAREDVT_FAILURE (*ip);
11665
11666                                 CHECK_STACK (1);
11667                                 --sp;
11668
11669                                 // FIXME:
11670                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11671                                 if (!src_var)
11672                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11673                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11674                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
11675                                 *sp++ = ins;
11676                                 ip += 2;
11677                                 break;
11678                         }
11679                         case CEE_READONLY_:
11680                                 readonly = TRUE;
11681                                 ip += 2;
11682                                 break;
11683
11684                         case CEE_UNUSED56:
11685                         case CEE_UNUSED57:
11686                         case CEE_UNUSED70:
11687                         case CEE_UNUSED:
11688                         case CEE_UNUSED99:
11689                                 UNVERIFIED;
11690                                 
11691                         default:
11692                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
11693                                 UNVERIFIED;
11694                         }
11695                         break;
11696                 }
11697                 case CEE_UNUSED58:
11698                 case CEE_UNUSED1:
11699                         UNVERIFIED;
11700
11701                 default:
11702                         g_warning ("opcode 0x%02x not handled", *ip);
11703                         UNVERIFIED;
11704                 }
11705         }
11706         if (start_new_bblock != 1)
11707                 UNVERIFIED;
11708
11709         bblock->cil_length = ip - bblock->cil_code;
11710         if (bblock->next_bb) {
11711                 /* This could already be set because of inlining, #693905 */
11712                 MonoBasicBlock *bb = bblock;
11713
11714                 while (bb->next_bb)
11715                         bb = bb->next_bb;
11716                 bb->next_bb = end_bblock;
11717         } else {
11718                 bblock->next_bb = end_bblock;
11719         }
11720
11721         if (cfg->lmf_var) {
11722                 cfg->cbb = init_localsbb;
11723                 emit_push_lmf (cfg);
11724         }
11725
11726         if (cfg->method == method && cfg->domainvar) {
11727                 MonoInst *store;
11728                 MonoInst *get_domain;
11729
11730                 cfg->cbb = init_localsbb;
11731
11732                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
11733                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
11734                 }
11735                 else {
11736                         get_domain->dreg = alloc_preg (cfg);
11737                         MONO_ADD_INS (cfg->cbb, get_domain);
11738                 }               
11739                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
11740                 MONO_ADD_INS (cfg->cbb, store);
11741         }
11742
11743 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
11744         if (cfg->compile_aot)
11745                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
11746                 mono_get_got_var (cfg);
11747 #endif
11748
11749         if (cfg->method == method && cfg->got_var)
11750                 mono_emit_load_got_addr (cfg);
11751
11752         if (init_locals) {
11753                 MonoInst *store;
11754
11755                 cfg->cbb = init_localsbb;
11756                 cfg->ip = NULL;
11757                 for (i = 0; i < header->num_locals; ++i) {
11758                         MonoType *ptype = header->locals [i];
11759                         int t = ptype->type;
11760                         dreg = cfg->locals [i]->dreg;
11761
11762                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
11763                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
11764                         if (ptype->byref) {
11765                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
11766                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
11767                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
11768                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
11769                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
11770                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
11771                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
11772                                 ins->type = STACK_R8;
11773                                 ins->inst_p0 = (void*)&r8_0;
11774                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
11775                                 MONO_ADD_INS (init_localsbb, ins);
11776                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
11777                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
11778                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
11779                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
11780                         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, ptype)) {
11781                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
11782                         } else {
11783                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
11784                         }
11785                 }
11786         }
11787
11788         if (cfg->init_ref_vars && cfg->method == method) {
11789                 /* Emit initialization for ref vars */
11790                 // FIXME: Avoid duplication initialization for IL locals.
11791                 for (i = 0; i < cfg->num_varinfo; ++i) {
11792                         MonoInst *ins = cfg->varinfo [i];
11793
11794                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
11795                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
11796                 }
11797         }
11798
11799         if (seq_points) {
11800                 MonoBasicBlock *bb;
11801
11802                 /*
11803                  * Make seq points at backward branch targets interruptable.
11804                  */
11805                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
11806                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
11807                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
11808         }
11809
11810         /* Add a sequence point for method entry/exit events */
11811         if (seq_points) {
11812                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
11813                 MONO_ADD_INS (init_localsbb, ins);
11814                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
11815                 MONO_ADD_INS (cfg->bb_exit, ins);
11816         }
11817
11818         /*
11819          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
11820          * the code they refer to was dead (#11880).
11821          */
11822         if (sym_seq_points) {
11823                 for (i = 0; i < header->code_size; ++i) {
11824                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
11825                                 MonoInst *ins;
11826
11827                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
11828                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
11829                         }
11830                 }
11831         }
11832
11833         cfg->ip = NULL;
11834
11835         if (cfg->method == method) {
11836                 MonoBasicBlock *bb;
11837                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11838                         bb->region = mono_find_block_region (cfg, bb->real_offset);
11839                         if (cfg->spvars)
11840                                 mono_create_spvar_for_region (cfg, bb->region);
11841                         if (cfg->verbose_level > 2)
11842                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
11843                 }
11844         }
11845
11846         g_slist_free (class_inits);
11847         dont_inline = g_list_remove (dont_inline, method);
11848
11849         if (inline_costs < 0) {
11850                 char *mname;
11851
11852                 /* Method is too large */
11853                 mname = mono_method_full_name (method, TRUE);
11854                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
11855                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
11856                 g_free (mname);
11857                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11858                 mono_basic_block_free (original_bb);
11859                 return -1;
11860         }
11861
11862         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
11863                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
11864
11865         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11866         mono_basic_block_free (original_bb);
11867         return inline_costs;
11868  
11869  exception_exit:
11870         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
11871         goto cleanup;
11872
11873  inline_failure:
11874         goto cleanup;
11875
11876  load_error:
11877         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
11878         goto cleanup;
11879
11880  unverified:
11881         set_exception_type_from_invalid_il (cfg, method, ip);
11882         goto cleanup;
11883
11884  cleanup:
11885         g_slist_free (class_inits);
11886         mono_basic_block_free (original_bb);
11887         dont_inline = g_list_remove (dont_inline, method);
11888         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11889         return -1;
11890 }
11891
11892 static int
11893 store_membase_reg_to_store_membase_imm (int opcode)
11894 {
11895         switch (opcode) {
11896         case OP_STORE_MEMBASE_REG:
11897                 return OP_STORE_MEMBASE_IMM;
11898         case OP_STOREI1_MEMBASE_REG:
11899                 return OP_STOREI1_MEMBASE_IMM;
11900         case OP_STOREI2_MEMBASE_REG:
11901                 return OP_STOREI2_MEMBASE_IMM;
11902         case OP_STOREI4_MEMBASE_REG:
11903                 return OP_STOREI4_MEMBASE_IMM;
11904         case OP_STOREI8_MEMBASE_REG:
11905                 return OP_STOREI8_MEMBASE_IMM;
11906         default:
11907                 g_assert_not_reached ();
11908         }
11909
11910         return -1;
11911 }               
11912
11913 int
11914 mono_op_to_op_imm (int opcode)
11915 {
11916         switch (opcode) {
11917         case OP_IADD:
11918                 return OP_IADD_IMM;
11919         case OP_ISUB:
11920                 return OP_ISUB_IMM;
11921         case OP_IDIV:
11922                 return OP_IDIV_IMM;
11923         case OP_IDIV_UN:
11924                 return OP_IDIV_UN_IMM;
11925         case OP_IREM:
11926                 return OP_IREM_IMM;
11927         case OP_IREM_UN:
11928                 return OP_IREM_UN_IMM;
11929         case OP_IMUL:
11930                 return OP_IMUL_IMM;
11931         case OP_IAND:
11932                 return OP_IAND_IMM;
11933         case OP_IOR:
11934                 return OP_IOR_IMM;
11935         case OP_IXOR:
11936                 return OP_IXOR_IMM;
11937         case OP_ISHL:
11938                 return OP_ISHL_IMM;
11939         case OP_ISHR:
11940                 return OP_ISHR_IMM;
11941         case OP_ISHR_UN:
11942                 return OP_ISHR_UN_IMM;
11943
11944         case OP_LADD:
11945                 return OP_LADD_IMM;
11946         case OP_LSUB:
11947                 return OP_LSUB_IMM;
11948         case OP_LAND:
11949                 return OP_LAND_IMM;
11950         case OP_LOR:
11951                 return OP_LOR_IMM;
11952         case OP_LXOR:
11953                 return OP_LXOR_IMM;
11954         case OP_LSHL:
11955                 return OP_LSHL_IMM;
11956         case OP_LSHR:
11957                 return OP_LSHR_IMM;
11958         case OP_LSHR_UN:
11959                 return OP_LSHR_UN_IMM;          
11960
11961         case OP_COMPARE:
11962                 return OP_COMPARE_IMM;
11963         case OP_ICOMPARE:
11964                 return OP_ICOMPARE_IMM;
11965         case OP_LCOMPARE:
11966                 return OP_LCOMPARE_IMM;
11967
11968         case OP_STORE_MEMBASE_REG:
11969                 return OP_STORE_MEMBASE_IMM;
11970         case OP_STOREI1_MEMBASE_REG:
11971                 return OP_STOREI1_MEMBASE_IMM;
11972         case OP_STOREI2_MEMBASE_REG:
11973                 return OP_STOREI2_MEMBASE_IMM;
11974         case OP_STOREI4_MEMBASE_REG:
11975                 return OP_STOREI4_MEMBASE_IMM;
11976
11977 #if defined(TARGET_X86) || defined (TARGET_AMD64)
11978         case OP_X86_PUSH:
11979                 return OP_X86_PUSH_IMM;
11980         case OP_X86_COMPARE_MEMBASE_REG:
11981                 return OP_X86_COMPARE_MEMBASE_IMM;
11982 #endif
11983 #if defined(TARGET_AMD64)
11984         case OP_AMD64_ICOMPARE_MEMBASE_REG:
11985                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
11986 #endif
11987         case OP_VOIDCALL_REG:
11988                 return OP_VOIDCALL;
11989         case OP_CALL_REG:
11990                 return OP_CALL;
11991         case OP_LCALL_REG:
11992                 return OP_LCALL;
11993         case OP_FCALL_REG:
11994                 return OP_FCALL;
11995         case OP_LOCALLOC:
11996                 return OP_LOCALLOC_IMM;
11997         }
11998
11999         return -1;
12000 }
12001
12002 static int
12003 ldind_to_load_membase (int opcode)
12004 {
12005         switch (opcode) {
12006         case CEE_LDIND_I1:
12007                 return OP_LOADI1_MEMBASE;
12008         case CEE_LDIND_U1:
12009                 return OP_LOADU1_MEMBASE;
12010         case CEE_LDIND_I2:
12011                 return OP_LOADI2_MEMBASE;
12012         case CEE_LDIND_U2:
12013                 return OP_LOADU2_MEMBASE;
12014         case CEE_LDIND_I4:
12015                 return OP_LOADI4_MEMBASE;
12016         case CEE_LDIND_U4:
12017                 return OP_LOADU4_MEMBASE;
12018         case CEE_LDIND_I:
12019                 return OP_LOAD_MEMBASE;
12020         case CEE_LDIND_REF:
12021                 return OP_LOAD_MEMBASE;
12022         case CEE_LDIND_I8:
12023                 return OP_LOADI8_MEMBASE;
12024         case CEE_LDIND_R4:
12025                 return OP_LOADR4_MEMBASE;
12026         case CEE_LDIND_R8:
12027                 return OP_LOADR8_MEMBASE;
12028         default:
12029                 g_assert_not_reached ();
12030         }
12031
12032         return -1;
12033 }
12034
12035 static int
12036 stind_to_store_membase (int opcode)
12037 {
12038         switch (opcode) {
12039         case CEE_STIND_I1:
12040                 return OP_STOREI1_MEMBASE_REG;
12041         case CEE_STIND_I2:
12042                 return OP_STOREI2_MEMBASE_REG;
12043         case CEE_STIND_I4:
12044                 return OP_STOREI4_MEMBASE_REG;
12045         case CEE_STIND_I:
12046         case CEE_STIND_REF:
12047                 return OP_STORE_MEMBASE_REG;
12048         case CEE_STIND_I8:
12049                 return OP_STOREI8_MEMBASE_REG;
12050         case CEE_STIND_R4:
12051                 return OP_STORER4_MEMBASE_REG;
12052         case CEE_STIND_R8:
12053                 return OP_STORER8_MEMBASE_REG;
12054         default:
12055                 g_assert_not_reached ();
12056         }
12057
12058         return -1;
12059 }
12060
12061 int
12062 mono_load_membase_to_load_mem (int opcode)
12063 {
12064         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12065 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12066         switch (opcode) {
12067         case OP_LOAD_MEMBASE:
12068                 return OP_LOAD_MEM;
12069         case OP_LOADU1_MEMBASE:
12070                 return OP_LOADU1_MEM;
12071         case OP_LOADU2_MEMBASE:
12072                 return OP_LOADU2_MEM;
12073         case OP_LOADI4_MEMBASE:
12074                 return OP_LOADI4_MEM;
12075         case OP_LOADU4_MEMBASE:
12076                 return OP_LOADU4_MEM;
12077 #if SIZEOF_REGISTER == 8
12078         case OP_LOADI8_MEMBASE:
12079                 return OP_LOADI8_MEM;
12080 #endif
12081         }
12082 #endif
12083
12084         return -1;
12085 }
12086
12087 static inline int
12088 op_to_op_dest_membase (int store_opcode, int opcode)
12089 {
12090 #if defined(TARGET_X86)
12091         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12092                 return -1;
12093
12094         switch (opcode) {
12095         case OP_IADD:
12096                 return OP_X86_ADD_MEMBASE_REG;
12097         case OP_ISUB:
12098                 return OP_X86_SUB_MEMBASE_REG;
12099         case OP_IAND:
12100                 return OP_X86_AND_MEMBASE_REG;
12101         case OP_IOR:
12102                 return OP_X86_OR_MEMBASE_REG;
12103         case OP_IXOR:
12104                 return OP_X86_XOR_MEMBASE_REG;
12105         case OP_ADD_IMM:
12106         case OP_IADD_IMM:
12107                 return OP_X86_ADD_MEMBASE_IMM;
12108         case OP_SUB_IMM:
12109         case OP_ISUB_IMM:
12110                 return OP_X86_SUB_MEMBASE_IMM;
12111         case OP_AND_IMM:
12112         case OP_IAND_IMM:
12113                 return OP_X86_AND_MEMBASE_IMM;
12114         case OP_OR_IMM:
12115         case OP_IOR_IMM:
12116                 return OP_X86_OR_MEMBASE_IMM;
12117         case OP_XOR_IMM:
12118         case OP_IXOR_IMM:
12119                 return OP_X86_XOR_MEMBASE_IMM;
12120         case OP_MOVE:
12121                 return OP_NOP;
12122         }
12123 #endif
12124
12125 #if defined(TARGET_AMD64)
12126         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12127                 return -1;
12128
12129         switch (opcode) {
12130         case OP_IADD:
12131                 return OP_X86_ADD_MEMBASE_REG;
12132         case OP_ISUB:
12133                 return OP_X86_SUB_MEMBASE_REG;
12134         case OP_IAND:
12135                 return OP_X86_AND_MEMBASE_REG;
12136         case OP_IOR:
12137                 return OP_X86_OR_MEMBASE_REG;
12138         case OP_IXOR:
12139                 return OP_X86_XOR_MEMBASE_REG;
12140         case OP_IADD_IMM:
12141                 return OP_X86_ADD_MEMBASE_IMM;
12142         case OP_ISUB_IMM:
12143                 return OP_X86_SUB_MEMBASE_IMM;
12144         case OP_IAND_IMM:
12145                 return OP_X86_AND_MEMBASE_IMM;
12146         case OP_IOR_IMM:
12147                 return OP_X86_OR_MEMBASE_IMM;
12148         case OP_IXOR_IMM:
12149                 return OP_X86_XOR_MEMBASE_IMM;
12150         case OP_LADD:
12151                 return OP_AMD64_ADD_MEMBASE_REG;
12152         case OP_LSUB:
12153                 return OP_AMD64_SUB_MEMBASE_REG;
12154         case OP_LAND:
12155                 return OP_AMD64_AND_MEMBASE_REG;
12156         case OP_LOR:
12157                 return OP_AMD64_OR_MEMBASE_REG;
12158         case OP_LXOR:
12159                 return OP_AMD64_XOR_MEMBASE_REG;
12160         case OP_ADD_IMM:
12161         case OP_LADD_IMM:
12162                 return OP_AMD64_ADD_MEMBASE_IMM;
12163         case OP_SUB_IMM:
12164         case OP_LSUB_IMM:
12165                 return OP_AMD64_SUB_MEMBASE_IMM;
12166         case OP_AND_IMM:
12167         case OP_LAND_IMM:
12168                 return OP_AMD64_AND_MEMBASE_IMM;
12169         case OP_OR_IMM:
12170         case OP_LOR_IMM:
12171                 return OP_AMD64_OR_MEMBASE_IMM;
12172         case OP_XOR_IMM:
12173         case OP_LXOR_IMM:
12174                 return OP_AMD64_XOR_MEMBASE_IMM;
12175         case OP_MOVE:
12176                 return OP_NOP;
12177         }
12178 #endif
12179
12180         return -1;
12181 }
12182
12183 static inline int
12184 op_to_op_store_membase (int store_opcode, int opcode)
12185 {
12186 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12187         switch (opcode) {
12188         case OP_ICEQ:
12189                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12190                         return OP_X86_SETEQ_MEMBASE;
12191         case OP_CNE:
12192                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12193                         return OP_X86_SETNE_MEMBASE;
12194         }
12195 #endif
12196
12197         return -1;
12198 }
12199
12200 static inline int
12201 op_to_op_src1_membase (int load_opcode, int opcode)
12202 {
12203 #ifdef TARGET_X86
12204         /* FIXME: This has sign extension issues */
12205         /*
12206         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12207                 return OP_X86_COMPARE_MEMBASE8_IMM;
12208         */
12209
12210         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12211                 return -1;
12212
12213         switch (opcode) {
12214         case OP_X86_PUSH:
12215                 return OP_X86_PUSH_MEMBASE;
12216         case OP_COMPARE_IMM:
12217         case OP_ICOMPARE_IMM:
12218                 return OP_X86_COMPARE_MEMBASE_IMM;
12219         case OP_COMPARE:
12220         case OP_ICOMPARE:
12221                 return OP_X86_COMPARE_MEMBASE_REG;
12222         }
12223 #endif
12224
12225 #ifdef TARGET_AMD64
12226         /* FIXME: This has sign extension issues */
12227         /*
12228         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12229                 return OP_X86_COMPARE_MEMBASE8_IMM;
12230         */
12231
12232         switch (opcode) {
12233         case OP_X86_PUSH:
12234 #ifdef __mono_ilp32__
12235                 if (load_opcode == OP_LOADI8_MEMBASE)
12236 #else
12237                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12238 #endif
12239                         return OP_X86_PUSH_MEMBASE;
12240                 break;
12241                 /* FIXME: This only works for 32 bit immediates
12242         case OP_COMPARE_IMM:
12243         case OP_LCOMPARE_IMM:
12244                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12245                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12246                 */
12247         case OP_ICOMPARE_IMM:
12248                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12249                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12250                 break;
12251         case OP_COMPARE:
12252         case OP_LCOMPARE:
12253 #ifdef __mono_ilp32__
12254                 if (load_opcode == OP_LOAD_MEMBASE)
12255                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12256                 if (load_opcode == OP_LOADI8_MEMBASE)
12257 #else
12258                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12259 #endif
12260                         return OP_AMD64_COMPARE_MEMBASE_REG;
12261                 break;
12262         case OP_ICOMPARE:
12263                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12264                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12265                 break;
12266         }
12267 #endif
12268
12269         return -1;
12270 }
12271
12272 static inline int
12273 op_to_op_src2_membase (int load_opcode, int opcode)
12274 {
12275 #ifdef TARGET_X86
12276         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12277                 return -1;
12278         
12279         switch (opcode) {
12280         case OP_COMPARE:
12281         case OP_ICOMPARE:
12282                 return OP_X86_COMPARE_REG_MEMBASE;
12283         case OP_IADD:
12284                 return OP_X86_ADD_REG_MEMBASE;
12285         case OP_ISUB:
12286                 return OP_X86_SUB_REG_MEMBASE;
12287         case OP_IAND:
12288                 return OP_X86_AND_REG_MEMBASE;
12289         case OP_IOR:
12290                 return OP_X86_OR_REG_MEMBASE;
12291         case OP_IXOR:
12292                 return OP_X86_XOR_REG_MEMBASE;
12293         }
12294 #endif
12295
12296 #ifdef TARGET_AMD64
12297 #ifdef __mono_ilp32__
12298         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12299 #else
12300         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12301 #endif
12302                 switch (opcode) {
12303                 case OP_ICOMPARE:
12304                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12305                 case OP_IADD:
12306                         return OP_X86_ADD_REG_MEMBASE;
12307                 case OP_ISUB:
12308                         return OP_X86_SUB_REG_MEMBASE;
12309                 case OP_IAND:
12310                         return OP_X86_AND_REG_MEMBASE;
12311                 case OP_IOR:
12312                         return OP_X86_OR_REG_MEMBASE;
12313                 case OP_IXOR:
12314                         return OP_X86_XOR_REG_MEMBASE;
12315                 }
12316 #ifdef __mono_ilp32__
12317         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12318 #else
12319         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12320 #endif
12321                 switch (opcode) {
12322                 case OP_COMPARE:
12323                 case OP_LCOMPARE:
12324                         return OP_AMD64_COMPARE_REG_MEMBASE;
12325                 case OP_LADD:
12326                         return OP_AMD64_ADD_REG_MEMBASE;
12327                 case OP_LSUB:
12328                         return OP_AMD64_SUB_REG_MEMBASE;
12329                 case OP_LAND:
12330                         return OP_AMD64_AND_REG_MEMBASE;
12331                 case OP_LOR:
12332                         return OP_AMD64_OR_REG_MEMBASE;
12333                 case OP_LXOR:
12334                         return OP_AMD64_XOR_REG_MEMBASE;
12335                 }
12336         }
12337 #endif
12338
12339         return -1;
12340 }
12341
12342 int
12343 mono_op_to_op_imm_noemul (int opcode)
12344 {
12345         switch (opcode) {
12346 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12347         case OP_LSHR:
12348         case OP_LSHL:
12349         case OP_LSHR_UN:
12350                 return -1;
12351 #endif
12352 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12353         case OP_IDIV:
12354         case OP_IDIV_UN:
12355         case OP_IREM:
12356         case OP_IREM_UN:
12357                 return -1;
12358 #endif
12359 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12360         case OP_IMUL:
12361                 return -1;
12362 #endif
12363         default:
12364                 return mono_op_to_op_imm (opcode);
12365         }
12366 }
12367
12368 /**
12369  * mono_handle_global_vregs:
12370  *
12371  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12372  * for them.
12373  */
12374 void
12375 mono_handle_global_vregs (MonoCompile *cfg)
12376 {
12377         gint32 *vreg_to_bb;
12378         MonoBasicBlock *bb;
12379         int i, pos;
12380
12381         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12382
12383 #ifdef MONO_ARCH_SIMD_INTRINSICS
12384         if (cfg->uses_simd_intrinsics)
12385                 mono_simd_simplify_indirection (cfg);
12386 #endif
12387
12388         /* Find local vregs used in more than one bb */
12389         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12390                 MonoInst *ins = bb->code;       
12391                 int block_num = bb->block_num;
12392
12393                 if (cfg->verbose_level > 2)
12394                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12395
12396                 cfg->cbb = bb;
12397                 for (; ins; ins = ins->next) {
12398                         const char *spec = INS_INFO (ins->opcode);
12399                         int regtype = 0, regindex;
12400                         gint32 prev_bb;
12401
12402                         if (G_UNLIKELY (cfg->verbose_level > 2))
12403                                 mono_print_ins (ins);
12404
12405                         g_assert (ins->opcode >= MONO_CEE_LAST);
12406
12407                         for (regindex = 0; regindex < 4; regindex ++) {
12408                                 int vreg = 0;
12409
12410                                 if (regindex == 0) {
12411                                         regtype = spec [MONO_INST_DEST];
12412                                         if (regtype == ' ')
12413                                                 continue;
12414                                         vreg = ins->dreg;
12415                                 } else if (regindex == 1) {
12416                                         regtype = spec [MONO_INST_SRC1];
12417                                         if (regtype == ' ')
12418                                                 continue;
12419                                         vreg = ins->sreg1;
12420                                 } else if (regindex == 2) {
12421                                         regtype = spec [MONO_INST_SRC2];
12422                                         if (regtype == ' ')
12423                                                 continue;
12424                                         vreg = ins->sreg2;
12425                                 } else if (regindex == 3) {
12426                                         regtype = spec [MONO_INST_SRC3];
12427                                         if (regtype == ' ')
12428                                                 continue;
12429                                         vreg = ins->sreg3;
12430                                 }
12431
12432 #if SIZEOF_REGISTER == 4
12433                                 /* In the LLVM case, the long opcodes are not decomposed */
12434                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12435                                         /*
12436                                          * Since some instructions reference the original long vreg,
12437                                          * and some reference the two component vregs, it is quite hard
12438                                          * to determine when it needs to be global. So be conservative.
12439                                          */
12440                                         if (!get_vreg_to_inst (cfg, vreg)) {
12441                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12442
12443                                                 if (cfg->verbose_level > 2)
12444                                                         printf ("LONG VREG R%d made global.\n", vreg);
12445                                         }
12446
12447                                         /*
12448                                          * Make the component vregs volatile since the optimizations can
12449                                          * get confused otherwise.
12450                                          */
12451                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12452                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12453                                 }
12454 #endif
12455
12456                                 g_assert (vreg != -1);
12457
12458                                 prev_bb = vreg_to_bb [vreg];
12459                                 if (prev_bb == 0) {
12460                                         /* 0 is a valid block num */
12461                                         vreg_to_bb [vreg] = block_num + 1;
12462                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12463                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12464                                                 continue;
12465
12466                                         if (!get_vreg_to_inst (cfg, vreg)) {
12467                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12468                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12469
12470                                                 switch (regtype) {
12471                                                 case 'i':
12472                                                         if (vreg_is_ref (cfg, vreg))
12473                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12474                                                         else
12475                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12476                                                         break;
12477                                                 case 'l':
12478                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12479                                                         break;
12480                                                 case 'f':
12481                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12482                                                         break;
12483                                                 case 'v':
12484                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12485                                                         break;
12486                                                 default:
12487                                                         g_assert_not_reached ();
12488                                                 }
12489                                         }
12490
12491                                         /* Flag as having been used in more than one bb */
12492                                         vreg_to_bb [vreg] = -1;
12493                                 }
12494                         }
12495                 }
12496         }
12497
12498         /* If a variable is used in only one bblock, convert it into a local vreg */
12499         for (i = 0; i < cfg->num_varinfo; i++) {
12500                 MonoInst *var = cfg->varinfo [i];
12501                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12502
12503                 switch (var->type) {
12504                 case STACK_I4:
12505                 case STACK_OBJ:
12506                 case STACK_PTR:
12507                 case STACK_MP:
12508                 case STACK_VTYPE:
12509 #if SIZEOF_REGISTER == 8
12510                 case STACK_I8:
12511 #endif
12512 #if !defined(TARGET_X86)
12513                 /* Enabling this screws up the fp stack on x86 */
12514                 case STACK_R8:
12515 #endif
12516                         if (mono_arch_is_soft_float ())
12517                                 break;
12518
12519                         /* Arguments are implicitly global */
12520                         /* Putting R4 vars into registers doesn't work currently */
12521                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12522                         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) {
12523                                 /* 
12524                                  * Make that the variable's liveness interval doesn't contain a call, since
12525                                  * that would cause the lvreg to be spilled, making the whole optimization
12526                                  * useless.
12527                                  */
12528                                 /* This is too slow for JIT compilation */
12529 #if 0
12530                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12531                                         MonoInst *ins;
12532                                         int def_index, call_index, ins_index;
12533                                         gboolean spilled = FALSE;
12534
12535                                         def_index = -1;
12536                                         call_index = -1;
12537                                         ins_index = 0;
12538                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12539                                                 const char *spec = INS_INFO (ins->opcode);
12540
12541                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12542                                                         def_index = ins_index;
12543
12544                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12545                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12546                                                         if (call_index > def_index) {
12547                                                                 spilled = TRUE;
12548                                                                 break;
12549                                                         }
12550                                                 }
12551
12552                                                 if (MONO_IS_CALL (ins))
12553                                                         call_index = ins_index;
12554
12555                                                 ins_index ++;
12556                                         }
12557
12558                                         if (spilled)
12559                                                 break;
12560                                 }
12561 #endif
12562
12563                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12564                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12565                                 var->flags |= MONO_INST_IS_DEAD;
12566                                 cfg->vreg_to_inst [var->dreg] = NULL;
12567                         }
12568                         break;
12569                 }
12570         }
12571
12572         /* 
12573          * Compress the varinfo and vars tables so the liveness computation is faster and
12574          * takes up less space.
12575          */
12576         pos = 0;
12577         for (i = 0; i < cfg->num_varinfo; ++i) {
12578                 MonoInst *var = cfg->varinfo [i];
12579                 if (pos < i && cfg->locals_start == i)
12580                         cfg->locals_start = pos;
12581                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12582                         if (pos < i) {
12583                                 cfg->varinfo [pos] = cfg->varinfo [i];
12584                                 cfg->varinfo [pos]->inst_c0 = pos;
12585                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12586                                 cfg->vars [pos].idx = pos;
12587 #if SIZEOF_REGISTER == 4
12588                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12589                                         /* Modify the two component vars too */
12590                                         MonoInst *var1;
12591
12592                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12593                                         var1->inst_c0 = pos;
12594                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12595                                         var1->inst_c0 = pos;
12596                                 }
12597 #endif
12598                         }
12599                         pos ++;
12600                 }
12601         }
12602         cfg->num_varinfo = pos;
12603         if (cfg->locals_start > cfg->num_varinfo)
12604                 cfg->locals_start = cfg->num_varinfo;
12605 }
12606
12607 /**
12608  * mono_spill_global_vars:
12609  *
12610  *   Generate spill code for variables which are not allocated to registers, 
12611  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12612  * code is generated which could be optimized by the local optimization passes.
12613  */
12614 void
12615 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12616 {
12617         MonoBasicBlock *bb;
12618         char spec2 [16];
12619         int orig_next_vreg;
12620         guint32 *vreg_to_lvreg;
12621         guint32 *lvregs;
12622         guint32 i, lvregs_len;
12623         gboolean dest_has_lvreg = FALSE;
12624         guint32 stacktypes [128];
12625         MonoInst **live_range_start, **live_range_end;
12626         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12627         int *gsharedvt_vreg_to_idx = NULL;
12628
12629         *need_local_opts = FALSE;
12630
12631         memset (spec2, 0, sizeof (spec2));
12632
12633         /* FIXME: Move this function to mini.c */
12634         stacktypes ['i'] = STACK_PTR;
12635         stacktypes ['l'] = STACK_I8;
12636         stacktypes ['f'] = STACK_R8;
12637 #ifdef MONO_ARCH_SIMD_INTRINSICS
12638         stacktypes ['x'] = STACK_VTYPE;
12639 #endif
12640
12641 #if SIZEOF_REGISTER == 4
12642         /* Create MonoInsts for longs */
12643         for (i = 0; i < cfg->num_varinfo; i++) {
12644                 MonoInst *ins = cfg->varinfo [i];
12645
12646                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12647                         switch (ins->type) {
12648                         case STACK_R8:
12649                         case STACK_I8: {
12650                                 MonoInst *tree;
12651
12652                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12653                                         break;
12654
12655                                 g_assert (ins->opcode == OP_REGOFFSET);
12656
12657                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12658                                 g_assert (tree);
12659                                 tree->opcode = OP_REGOFFSET;
12660                                 tree->inst_basereg = ins->inst_basereg;
12661                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12662
12663                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12664                                 g_assert (tree);
12665                                 tree->opcode = OP_REGOFFSET;
12666                                 tree->inst_basereg = ins->inst_basereg;
12667                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12668                                 break;
12669                         }
12670                         default:
12671                                 break;
12672                         }
12673                 }
12674         }
12675 #endif
12676
12677         if (cfg->compute_gc_maps) {
12678                 /* registers need liveness info even for !non refs */
12679                 for (i = 0; i < cfg->num_varinfo; i++) {
12680                         MonoInst *ins = cfg->varinfo [i];
12681
12682                         if (ins->opcode == OP_REGVAR)
12683                                 ins->flags |= MONO_INST_GC_TRACK;
12684                 }
12685         }
12686
12687         if (cfg->gsharedvt) {
12688                 gsharedvt_vreg_to_idx = g_new0 (int, cfg->next_vreg);
12689
12690                 for (i = 0; i < cfg->num_varinfo; ++i) {
12691                         MonoInst *ins = cfg->varinfo [i];
12692                         int idx;
12693
12694                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12695                                 if (i >= cfg->locals_start) {
12696                                         /* Local */
12697                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
12698                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
12699                                         ins->opcode = OP_GSHAREDVT_LOCAL;
12700                                         ins->inst_imm = idx;
12701                                 } else {
12702                                         /* Arg */
12703                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
12704                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
12705                                 }
12706                         }
12707                 }
12708         }
12709                 
12710         /* FIXME: widening and truncation */
12711
12712         /*
12713          * As an optimization, when a variable allocated to the stack is first loaded into 
12714          * an lvreg, we will remember the lvreg and use it the next time instead of loading
12715          * the variable again.
12716          */
12717         orig_next_vreg = cfg->next_vreg;
12718         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
12719         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
12720         lvregs_len = 0;
12721
12722         /* 
12723          * These arrays contain the first and last instructions accessing a given
12724          * variable.
12725          * Since we emit bblocks in the same order we process them here, and we
12726          * don't split live ranges, these will precisely describe the live range of
12727          * the variable, i.e. the instruction range where a valid value can be found
12728          * in the variables location.
12729          * The live range is computed using the liveness info computed by the liveness pass.
12730          * We can't use vmv->range, since that is an abstract live range, and we need
12731          * one which is instruction precise.
12732          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
12733          */
12734         /* FIXME: Only do this if debugging info is requested */
12735         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
12736         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
12737         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12738         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12739         
12740         /* Add spill loads/stores */
12741         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12742                 MonoInst *ins;
12743
12744                 if (cfg->verbose_level > 2)
12745                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
12746
12747                 /* Clear vreg_to_lvreg array */
12748                 for (i = 0; i < lvregs_len; i++)
12749                         vreg_to_lvreg [lvregs [i]] = 0;
12750                 lvregs_len = 0;
12751
12752                 cfg->cbb = bb;
12753                 MONO_BB_FOR_EACH_INS (bb, ins) {
12754                         const char *spec = INS_INFO (ins->opcode);
12755                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
12756                         gboolean store, no_lvreg;
12757                         int sregs [MONO_MAX_SRC_REGS];
12758
12759                         if (G_UNLIKELY (cfg->verbose_level > 2))
12760                                 mono_print_ins (ins);
12761
12762                         if (ins->opcode == OP_NOP)
12763                                 continue;
12764
12765                         /* 
12766                          * We handle LDADDR here as well, since it can only be decomposed
12767                          * when variable addresses are known.
12768                          */
12769                         if (ins->opcode == OP_LDADDR) {
12770                                 MonoInst *var = ins->inst_p0;
12771
12772                                 if (var->opcode == OP_VTARG_ADDR) {
12773                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
12774                                         MonoInst *vtaddr = var->inst_left;
12775                                         if (vtaddr->opcode == OP_REGVAR) {
12776                                                 ins->opcode = OP_MOVE;
12777                                                 ins->sreg1 = vtaddr->dreg;
12778                                         }
12779                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
12780                                                 ins->opcode = OP_LOAD_MEMBASE;
12781                                                 ins->inst_basereg = vtaddr->inst_basereg;
12782                                                 ins->inst_offset = vtaddr->inst_offset;
12783                                         } else
12784                                                 NOT_IMPLEMENTED;
12785                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
12786                                         /* gsharedvt arg passed by ref */
12787                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
12788
12789                                         ins->opcode = OP_LOAD_MEMBASE;
12790                                         ins->inst_basereg = var->inst_basereg;
12791                                         ins->inst_offset = var->inst_offset;
12792                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
12793                                         MonoInst *load, *load2, *load3;
12794                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
12795                                         int reg1, reg2, reg3;
12796                                         MonoInst *info_var = cfg->gsharedvt_info_var;
12797                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
12798
12799                                         /*
12800                                          * gsharedvt local.
12801                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
12802                                          */
12803
12804                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
12805
12806                                         g_assert (info_var);
12807                                         g_assert (locals_var);
12808
12809                                         /* Mark the instruction used to compute the locals var as used */
12810                                         cfg->gsharedvt_locals_var_ins = NULL;
12811
12812                                         /* Load the offset */
12813                                         if (info_var->opcode == OP_REGOFFSET) {
12814                                                 reg1 = alloc_ireg (cfg);
12815                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
12816                                         } else if (info_var->opcode == OP_REGVAR) {
12817                                                 load = NULL;
12818                                                 reg1 = info_var->dreg;
12819                                         } else {
12820                                                 g_assert_not_reached ();
12821                                         }
12822                                         reg2 = alloc_ireg (cfg);
12823                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
12824                                         /* Load the locals area address */
12825                                         reg3 = alloc_ireg (cfg);
12826                                         if (locals_var->opcode == OP_REGOFFSET) {
12827                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
12828                                         } else if (locals_var->opcode == OP_REGVAR) {
12829                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
12830                                         } else {
12831                                                 g_assert_not_reached ();
12832                                         }
12833                                         /* Compute the address */
12834                                         ins->opcode = OP_PADD;
12835                                         ins->sreg1 = reg3;
12836                                         ins->sreg2 = reg2;
12837
12838                                         mono_bblock_insert_before_ins (bb, ins, load3);
12839                                         mono_bblock_insert_before_ins (bb, load3, load2);
12840                                         if (load)
12841                                                 mono_bblock_insert_before_ins (bb, load2, load);
12842                                 } else {
12843                                         g_assert (var->opcode == OP_REGOFFSET);
12844
12845                                         ins->opcode = OP_ADD_IMM;
12846                                         ins->sreg1 = var->inst_basereg;
12847                                         ins->inst_imm = var->inst_offset;
12848                                 }
12849
12850                                 *need_local_opts = TRUE;
12851                                 spec = INS_INFO (ins->opcode);
12852                         }
12853
12854                         if (ins->opcode < MONO_CEE_LAST) {
12855                                 mono_print_ins (ins);
12856                                 g_assert_not_reached ();
12857                         }
12858
12859                         /*
12860                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
12861                          * src register.
12862                          * FIXME:
12863                          */
12864                         if (MONO_IS_STORE_MEMBASE (ins)) {
12865                                 tmp_reg = ins->dreg;
12866                                 ins->dreg = ins->sreg2;
12867                                 ins->sreg2 = tmp_reg;
12868                                 store = TRUE;
12869
12870                                 spec2 [MONO_INST_DEST] = ' ';
12871                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
12872                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
12873                                 spec2 [MONO_INST_SRC3] = ' ';
12874                                 spec = spec2;
12875                         } else if (MONO_IS_STORE_MEMINDEX (ins))
12876                                 g_assert_not_reached ();
12877                         else
12878                                 store = FALSE;
12879                         no_lvreg = FALSE;
12880
12881                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
12882                                 printf ("\t %.3s %d", spec, ins->dreg);
12883                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
12884                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
12885                                         printf (" %d", sregs [srcindex]);
12886                                 printf ("\n");
12887                         }
12888
12889                         /***************/
12890                         /*    DREG     */
12891                         /***************/
12892                         regtype = spec [MONO_INST_DEST];
12893                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
12894                         prev_dreg = -1;
12895
12896                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
12897                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
12898                                 MonoInst *store_ins;
12899                                 int store_opcode;
12900                                 MonoInst *def_ins = ins;
12901                                 int dreg = ins->dreg; /* The original vreg */
12902
12903                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
12904
12905                                 if (var->opcode == OP_REGVAR) {
12906                                         ins->dreg = var->dreg;
12907                                 } 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)) {
12908                                         /* 
12909                                          * Instead of emitting a load+store, use a _membase opcode.
12910                                          */
12911                                         g_assert (var->opcode == OP_REGOFFSET);
12912                                         if (ins->opcode == OP_MOVE) {
12913                                                 NULLIFY_INS (ins);
12914                                                 def_ins = NULL;
12915                                         } else {
12916                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
12917                                                 ins->inst_basereg = var->inst_basereg;
12918                                                 ins->inst_offset = var->inst_offset;
12919                                                 ins->dreg = -1;
12920                                         }
12921                                         spec = INS_INFO (ins->opcode);
12922                                 } else {
12923                                         guint32 lvreg;
12924
12925                                         g_assert (var->opcode == OP_REGOFFSET);
12926
12927                                         prev_dreg = ins->dreg;
12928
12929                                         /* Invalidate any previous lvreg for this vreg */
12930                                         vreg_to_lvreg [ins->dreg] = 0;
12931
12932                                         lvreg = 0;
12933
12934                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
12935                                                 regtype = 'l';
12936                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
12937                                         }
12938
12939                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
12940
12941 #if SIZEOF_REGISTER != 8
12942                                         if (regtype == 'l') {
12943                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
12944                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
12945                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
12946                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
12947                                                 def_ins = store_ins;
12948                                         }
12949                                         else
12950 #endif
12951                                         {
12952                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
12953
12954                                                 /* Try to fuse the store into the instruction itself */
12955                                                 /* FIXME: Add more instructions */
12956                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
12957                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
12958                                                         ins->inst_imm = ins->inst_c0;
12959                                                         ins->inst_destbasereg = var->inst_basereg;
12960                                                         ins->inst_offset = var->inst_offset;
12961                                                         spec = INS_INFO (ins->opcode);
12962                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
12963                                                         ins->opcode = store_opcode;
12964                                                         ins->inst_destbasereg = var->inst_basereg;
12965                                                         ins->inst_offset = var->inst_offset;
12966
12967                                                         no_lvreg = TRUE;
12968
12969                                                         tmp_reg = ins->dreg;
12970                                                         ins->dreg = ins->sreg2;
12971                                                         ins->sreg2 = tmp_reg;
12972                                                         store = TRUE;
12973
12974                                                         spec2 [MONO_INST_DEST] = ' ';
12975                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
12976                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
12977                                                         spec2 [MONO_INST_SRC3] = ' ';
12978                                                         spec = spec2;
12979                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
12980                                                         // FIXME: The backends expect the base reg to be in inst_basereg
12981                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
12982                                                         ins->dreg = -1;
12983                                                         ins->inst_basereg = var->inst_basereg;
12984                                                         ins->inst_offset = var->inst_offset;
12985                                                         spec = INS_INFO (ins->opcode);
12986                                                 } else {
12987                                                         /* printf ("INS: "); mono_print_ins (ins); */
12988                                                         /* Create a store instruction */
12989                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
12990
12991                                                         /* Insert it after the instruction */
12992                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
12993
12994                                                         def_ins = store_ins;
12995
12996                                                         /* 
12997                                                          * We can't assign ins->dreg to var->dreg here, since the
12998                                                          * sregs could use it. So set a flag, and do it after
12999                                                          * the sregs.
13000                                                          */
13001                                                         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)))
13002                                                                 dest_has_lvreg = TRUE;
13003                                                 }
13004                                         }
13005                                 }
13006
13007                                 if (def_ins && !live_range_start [dreg]) {
13008                                         live_range_start [dreg] = def_ins;
13009                                         live_range_start_bb [dreg] = bb;
13010                                 }
13011
13012                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13013                                         MonoInst *tmp;
13014
13015                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13016                                         tmp->inst_c1 = dreg;
13017                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13018                                 }
13019                         }
13020
13021                         /************/
13022                         /*  SREGS   */
13023                         /************/
13024                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13025                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13026                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13027                                 sreg = sregs [srcindex];
13028
13029                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13030                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13031                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13032                                         MonoInst *use_ins = ins;
13033                                         MonoInst *load_ins;
13034                                         guint32 load_opcode;
13035
13036                                         if (var->opcode == OP_REGVAR) {
13037                                                 sregs [srcindex] = var->dreg;
13038                                                 //mono_inst_set_src_registers (ins, sregs);
13039                                                 live_range_end [sreg] = use_ins;
13040                                                 live_range_end_bb [sreg] = bb;
13041
13042                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13043                                                         MonoInst *tmp;
13044
13045                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13046                                                         /* var->dreg is a hreg */
13047                                                         tmp->inst_c1 = sreg;
13048                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13049                                                 }
13050
13051                                                 continue;
13052                                         }
13053
13054                                         g_assert (var->opcode == OP_REGOFFSET);
13055                                                 
13056                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13057
13058                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13059
13060                                         if (vreg_to_lvreg [sreg]) {
13061                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13062
13063                                                 /* The variable is already loaded to an lvreg */
13064                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13065                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13066                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13067                                                 //mono_inst_set_src_registers (ins, sregs);
13068                                                 continue;
13069                                         }
13070
13071                                         /* Try to fuse the load into the instruction */
13072                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13073                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13074                                                 sregs [0] = var->inst_basereg;
13075                                                 //mono_inst_set_src_registers (ins, sregs);
13076                                                 ins->inst_offset = var->inst_offset;
13077                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13078                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13079                                                 sregs [1] = var->inst_basereg;
13080                                                 //mono_inst_set_src_registers (ins, sregs);
13081                                                 ins->inst_offset = var->inst_offset;
13082                                         } else {
13083                                                 if (MONO_IS_REAL_MOVE (ins)) {
13084                                                         ins->opcode = OP_NOP;
13085                                                         sreg = ins->dreg;
13086                                                 } else {
13087                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13088
13089                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13090
13091                                                         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) {
13092                                                                 if (var->dreg == prev_dreg) {
13093                                                                         /*
13094                                                                          * sreg refers to the value loaded by the load
13095                                                                          * emitted below, but we need to use ins->dreg
13096                                                                          * since it refers to the store emitted earlier.
13097                                                                          */
13098                                                                         sreg = ins->dreg;
13099                                                                 }
13100                                                                 g_assert (sreg != -1);
13101                                                                 vreg_to_lvreg [var->dreg] = sreg;
13102                                                                 g_assert (lvregs_len < 1024);
13103                                                                 lvregs [lvregs_len ++] = var->dreg;
13104                                                         }
13105                                                 }
13106
13107                                                 sregs [srcindex] = sreg;
13108                                                 //mono_inst_set_src_registers (ins, sregs);
13109
13110 #if SIZEOF_REGISTER != 8
13111                                                 if (regtype == 'l') {
13112                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13113                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13114                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13115                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13116                                                         use_ins = load_ins;
13117                                                 }
13118                                                 else
13119 #endif
13120                                                 {
13121 #if SIZEOF_REGISTER == 4
13122                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13123 #endif
13124                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13125                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13126                                                         use_ins = load_ins;
13127                                                 }
13128                                         }
13129
13130                                         if (var->dreg < orig_next_vreg) {
13131                                                 live_range_end [var->dreg] = use_ins;
13132                                                 live_range_end_bb [var->dreg] = bb;
13133                                         }
13134
13135                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13136                                                 MonoInst *tmp;
13137
13138                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13139                                                 tmp->inst_c1 = var->dreg;
13140                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13141                                         }
13142                                 }
13143                         }
13144                         mono_inst_set_src_registers (ins, sregs);
13145
13146                         if (dest_has_lvreg) {
13147                                 g_assert (ins->dreg != -1);
13148                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13149                                 g_assert (lvregs_len < 1024);
13150                                 lvregs [lvregs_len ++] = prev_dreg;
13151                                 dest_has_lvreg = FALSE;
13152                         }
13153
13154                         if (store) {
13155                                 tmp_reg = ins->dreg;
13156                                 ins->dreg = ins->sreg2;
13157                                 ins->sreg2 = tmp_reg;
13158                         }
13159
13160                         if (MONO_IS_CALL (ins)) {
13161                                 /* Clear vreg_to_lvreg array */
13162                                 for (i = 0; i < lvregs_len; i++)
13163                                         vreg_to_lvreg [lvregs [i]] = 0;
13164                                 lvregs_len = 0;
13165                         } else if (ins->opcode == OP_NOP) {
13166                                 ins->dreg = -1;
13167                                 MONO_INST_NULLIFY_SREGS (ins);
13168                         }
13169
13170                         if (cfg->verbose_level > 2)
13171                                 mono_print_ins_index (1, ins);
13172                 }
13173
13174                 /* Extend the live range based on the liveness info */
13175                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13176                         for (i = 0; i < cfg->num_varinfo; i ++) {
13177                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13178
13179                                 if (vreg_is_volatile (cfg, vi->vreg))
13180                                         /* The liveness info is incomplete */
13181                                         continue;
13182
13183                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13184                                         /* Live from at least the first ins of this bb */
13185                                         live_range_start [vi->vreg] = bb->code;
13186                                         live_range_start_bb [vi->vreg] = bb;
13187                                 }
13188
13189                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13190                                         /* Live at least until the last ins of this bb */
13191                                         live_range_end [vi->vreg] = bb->last_ins;
13192                                         live_range_end_bb [vi->vreg] = bb;
13193                                 }
13194                         }
13195                 }
13196         }
13197         
13198 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13199         /*
13200          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13201          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13202          */
13203         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13204                 for (i = 0; i < cfg->num_varinfo; ++i) {
13205                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13206                         MonoInst *ins;
13207
13208                         if (live_range_start [vreg]) {
13209                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13210                                 ins->inst_c0 = i;
13211                                 ins->inst_c1 = vreg;
13212                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13213                         }
13214                         if (live_range_end [vreg]) {
13215                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13216                                 ins->inst_c0 = i;
13217                                 ins->inst_c1 = vreg;
13218                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13219                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13220                                 else
13221                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13222                         }
13223                 }
13224         }
13225 #endif
13226
13227         if (cfg->gsharedvt_locals_var_ins) {
13228                 /* Nullify if unused */
13229                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13230                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13231         }
13232
13233         g_free (live_range_start);
13234         g_free (live_range_end);
13235         g_free (live_range_start_bb);
13236         g_free (live_range_end_bb);
13237 }
13238
13239 /**
13240  * FIXME:
13241  * - use 'iadd' instead of 'int_add'
13242  * - handling ovf opcodes: decompose in method_to_ir.
13243  * - unify iregs/fregs
13244  *   -> partly done, the missing parts are:
13245  *   - a more complete unification would involve unifying the hregs as well, so
13246  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13247  *     would no longer map to the machine hregs, so the code generators would need to
13248  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13249  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13250  *     fp/non-fp branches speeds it up by about 15%.
13251  * - use sext/zext opcodes instead of shifts
13252  * - add OP_ICALL
13253  * - get rid of TEMPLOADs if possible and use vregs instead
13254  * - clean up usage of OP_P/OP_ opcodes
13255  * - cleanup usage of DUMMY_USE
13256  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13257  *   stack
13258  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13259  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13260  * - make sure handle_stack_args () is called before the branch is emitted
13261  * - when the new IR is done, get rid of all unused stuff
13262  * - COMPARE/BEQ as separate instructions or unify them ?
13263  *   - keeping them separate allows specialized compare instructions like
13264  *     compare_imm, compare_membase
13265  *   - most back ends unify fp compare+branch, fp compare+ceq
13266  * - integrate mono_save_args into inline_method
13267  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13268  * - handle long shift opts on 32 bit platforms somehow: they require 
13269  *   3 sregs (2 for arg1 and 1 for arg2)
13270  * - make byref a 'normal' type.
13271  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13272  *   variable if needed.
13273  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13274  *   like inline_method.
13275  * - remove inlining restrictions
13276  * - fix LNEG and enable cfold of INEG
13277  * - generalize x86 optimizations like ldelema as a peephole optimization
13278  * - add store_mem_imm for amd64
13279  * - optimize the loading of the interruption flag in the managed->native wrappers
13280  * - avoid special handling of OP_NOP in passes
13281  * - move code inserting instructions into one function/macro.
13282  * - try a coalescing phase after liveness analysis
13283  * - add float -> vreg conversion + local optimizations on !x86
13284  * - figure out how to handle decomposed branches during optimizations, ie.
13285  *   compare+branch, op_jump_table+op_br etc.
13286  * - promote RuntimeXHandles to vregs
13287  * - vtype cleanups:
13288  *   - add a NEW_VARLOADA_VREG macro
13289  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13290  *   accessing vtype fields.
13291  * - get rid of I8CONST on 64 bit platforms
13292  * - dealing with the increase in code size due to branches created during opcode
13293  *   decomposition:
13294  *   - use extended basic blocks
13295  *     - all parts of the JIT
13296  *     - handle_global_vregs () && local regalloc
13297  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13298  * - sources of increase in code size:
13299  *   - vtypes
13300  *   - long compares
13301  *   - isinst and castclass
13302  *   - lvregs not allocated to global registers even if used multiple times
13303  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13304  *   meaningful.
13305  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13306  * - add all micro optimizations from the old JIT
13307  * - put tree optimizations into the deadce pass
13308  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13309  *   specific function.
13310  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13311  *   fcompare + branchCC.
13312  * - create a helper function for allocating a stack slot, taking into account 
13313  *   MONO_CFG_HAS_SPILLUP.
13314  * - merge r68207.
13315  * - merge the ia64 switch changes.
13316  * - optimize mono_regstate2_alloc_int/float.
13317  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13318  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13319  *   parts of the tree could be separated by other instructions, killing the tree
13320  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13321  *   instructions if the result of the load is used multiple times ?
13322  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13323  * - LAST MERGE: 108395.
13324  * - when returning vtypes in registers, generate IR and append it to the end of the
13325  *   last bb instead of doing it in the epilog.
13326  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13327  */
13328
13329 /*
13330
13331 NOTES
13332 -----
13333
13334 - When to decompose opcodes:
13335   - earlier: this makes some optimizations hard to implement, since the low level IR
13336   no longer contains the neccessary information. But it is easier to do.
13337   - later: harder to implement, enables more optimizations.
13338 - Branches inside bblocks:
13339   - created when decomposing complex opcodes. 
13340     - branches to another bblock: harmless, but not tracked by the branch 
13341       optimizations, so need to branch to a label at the start of the bblock.
13342     - branches to inside the same bblock: very problematic, trips up the local
13343       reg allocator. Can be fixed by spitting the current bblock, but that is a
13344       complex operation, since some local vregs can become global vregs etc.
13345 - Local/global vregs:
13346   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13347     local register allocator.
13348   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13349     structure, created by mono_create_var (). Assigned to hregs or the stack by
13350     the global register allocator.
13351 - When to do optimizations like alu->alu_imm:
13352   - earlier -> saves work later on since the IR will be smaller/simpler
13353   - later -> can work on more instructions
13354 - Handling of valuetypes:
13355   - When a vtype is pushed on the stack, a new temporary is created, an 
13356     instruction computing its address (LDADDR) is emitted and pushed on
13357     the stack. Need to optimize cases when the vtype is used immediately as in
13358     argument passing, stloc etc.
13359 - Instead of the to_end stuff in the old JIT, simply call the function handling
13360   the values on the stack before emitting the last instruction of the bb.
13361 */
13362
13363 #endif /* DISABLE_JIT */