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