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