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