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