Merge branch 'master' of github.com:mono/mono into masterwork
[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                                         MonoInst *val = sp [fsig->param_count];
6991
6992                                         if (val->type == STACK_OBJ) {
6993                                                 MonoInst *iargs [2];
6994
6995                                                 iargs [0] = sp [0];
6996                                                 iargs [1] = val;
6997                                                 
6998                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
6999                                         }
7000                                         
7001                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
7002                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
7003                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
7004                                                 emit_write_barrier (cfg, addr, val, 0);
7005                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
7006                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
7007
7008                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
7009
7010                                         *sp++ = ins;
7011                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
7012                                         if (!cmethod->klass->element_class->valuetype && !readonly)
7013                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
7014                                         CHECK_TYPELOAD (cmethod->klass);
7015                                         
7016                                         readonly = FALSE;
7017                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
7018                                         *sp++ = addr;
7019                                 } else {
7020                                         g_assert_not_reached ();
7021                                 }
7022
7023                                 CHECK_CFG_EXCEPTION;
7024
7025                                 ip += 5;
7026                                 ins_flag = 0;
7027                                 break;
7028                         }
7029
7030                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
7031                         if (ins) {
7032                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
7033                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
7034
7035                                 CHECK_CFG_EXCEPTION;
7036
7037                                 ip += 5;
7038                                 ins_flag = 0;
7039                                 break;
7040                         }
7041
7042                         /* Tail prefix / tail call optimization */
7043
7044                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
7045                         /* FIXME: runtime generic context pointer for jumps? */
7046                         /* FIXME: handle this for generic sharing eventually */
7047                         supported_tail_call = cmethod && 
7048                                 ((((ins_flag & MONO_INST_TAILCALL) && (*ip == CEE_CALL))
7049                                   ))//|| ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && ip [5] == CEE_RET))
7050                                 && !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig);
7051
7052                         if (supported_tail_call) {
7053                                 MonoCallInst *call;
7054
7055                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
7056                                 INLINE_FAILURE;
7057
7058                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7059
7060 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
7061                                 /* Handle tail calls similarly to calls */
7062                                 call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
7063 #else
7064                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7065                                 call->tail_call = TRUE;
7066                                 call->method = cmethod;
7067                                 call->signature = mono_method_signature (cmethod);
7068
7069                                 /*
7070                                  * We implement tail calls by storing the actual arguments into the 
7071                                  * argument variables, then emitting a CEE_JMP.
7072                                  */
7073                                 for (i = 0; i < n; ++i) {
7074                                         /* Prevent argument from being register allocated */
7075                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7076                                         EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
7077                                 }
7078 #endif
7079
7080                                 ins = (MonoInst*)call;
7081                                 ins->inst_p0 = cmethod;
7082                                 ins->inst_p1 = arg_array [0];
7083                                 MONO_ADD_INS (bblock, ins);
7084                                 link_bblock (cfg, bblock, end_bblock);                  
7085                                 start_new_bblock = 1;
7086
7087                                 CHECK_CFG_EXCEPTION;
7088
7089                                 ip += 5;
7090                                 ins_flag = 0;
7091
7092                                 // FIXME: Eliminate unreachable epilogs
7093
7094                                 /*
7095                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
7096                                  * only reachable from this call.
7097                                  */
7098                                 GET_BBLOCK (cfg, tblock, ip);
7099                                 if (tblock == bblock || tblock->in_count == 0)
7100                                         ip += 1;
7101                                 break;
7102                         }
7103
7104                         /* Common call */
7105                         INLINE_FAILURE;
7106                         if (vtable_arg) {
7107                                 ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
7108                                         NULL, vtable_arg);
7109                         } else if (imt_arg) {
7110                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
7111                         } else {
7112                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
7113                         }
7114
7115                         if (!MONO_TYPE_IS_VOID (fsig->ret))
7116                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
7117
7118                         CHECK_CFG_EXCEPTION;
7119
7120                         ip += 5;
7121                         ins_flag = 0;
7122                         break;
7123                 }
7124                 case CEE_RET:
7125                         if (cfg->method != method) {
7126                                 /* return from inlined method */
7127                                 /* 
7128                                  * If in_count == 0, that means the ret is unreachable due to
7129                                  * being preceeded by a throw. In that case, inline_method () will
7130                                  * handle setting the return value 
7131                                  * (test case: test_0_inline_throw ()).
7132                                  */
7133                                 if (return_var && cfg->cbb->in_count) {
7134                                         MonoInst *store;
7135                                         CHECK_STACK (1);
7136                                         --sp;
7137                                         //g_assert (returnvar != -1);
7138                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
7139                                         cfg->ret_var_set = TRUE;
7140                                 } 
7141                         } else {
7142                                 if (cfg->ret) {
7143                                         MonoType *ret_type = mono_method_signature (method)->ret;
7144
7145                                         if (seq_points) {
7146                                                 /* 
7147                                                  * Place a seq point here too even through the IL stack is not
7148                                                  * empty, so a step over on
7149                                                  * call <FOO>
7150                                                  * ret
7151                                                  * will work correctly.
7152                                                  */
7153                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
7154                                                 MONO_ADD_INS (cfg->cbb, ins);
7155                                         }
7156
7157                                         g_assert (!return_var);
7158                                         CHECK_STACK (1);
7159                                         --sp;
7160
7161                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
7162                                                 UNVERIFIED;
7163
7164                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7165                                                 MonoInst *ret_addr;
7166
7167                                                 if (!cfg->vret_addr) {
7168                                                         MonoInst *ins;
7169
7170                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
7171                                                 } else {
7172                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7173
7174                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
7175                                                         ins->klass = mono_class_from_mono_type (ret_type);
7176                                                 }
7177                                         } else {
7178 #ifdef MONO_ARCH_SOFT_FLOAT
7179                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7180                                                         MonoInst *iargs [1];
7181                                                         MonoInst *conv;
7182
7183                                                         iargs [0] = *sp;
7184                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7185                                                         mono_arch_emit_setret (cfg, method, conv);
7186                                                 } else {
7187                                                         mono_arch_emit_setret (cfg, method, *sp);
7188                                                 }
7189 #else
7190                                                 mono_arch_emit_setret (cfg, method, *sp);
7191 #endif
7192                                         }
7193                                 }
7194                         }
7195                         if (sp != stack_start)
7196                                 UNVERIFIED;
7197                         MONO_INST_NEW (cfg, ins, OP_BR);
7198                         ip++;
7199                         ins->inst_target_bb = end_bblock;
7200                         MONO_ADD_INS (bblock, ins);
7201                         link_bblock (cfg, bblock, end_bblock);
7202                         start_new_bblock = 1;
7203                         break;
7204                 case CEE_BR_S:
7205                         CHECK_OPSIZE (2);
7206                         MONO_INST_NEW (cfg, ins, OP_BR);
7207                         ip++;
7208                         target = ip + 1 + (signed char)(*ip);
7209                         ++ip;
7210                         GET_BBLOCK (cfg, tblock, target);
7211                         link_bblock (cfg, bblock, tblock);
7212                         ins->inst_target_bb = tblock;
7213                         if (sp != stack_start) {
7214                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7215                                 sp = stack_start;
7216                                 CHECK_UNVERIFIABLE (cfg);
7217                         }
7218                         MONO_ADD_INS (bblock, ins);
7219                         start_new_bblock = 1;
7220                         inline_costs += BRANCH_COST;
7221                         break;
7222                 case CEE_BEQ_S:
7223                 case CEE_BGE_S:
7224                 case CEE_BGT_S:
7225                 case CEE_BLE_S:
7226                 case CEE_BLT_S:
7227                 case CEE_BNE_UN_S:
7228                 case CEE_BGE_UN_S:
7229                 case CEE_BGT_UN_S:
7230                 case CEE_BLE_UN_S:
7231                 case CEE_BLT_UN_S:
7232                         CHECK_OPSIZE (2);
7233                         CHECK_STACK (2);
7234                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
7235                         ip++;
7236                         target = ip + 1 + *(signed char*)ip;
7237                         ip++;
7238
7239                         ADD_BINCOND (NULL);
7240
7241                         sp = stack_start;
7242                         inline_costs += BRANCH_COST;
7243                         break;
7244                 case CEE_BR:
7245                         CHECK_OPSIZE (5);
7246                         MONO_INST_NEW (cfg, ins, OP_BR);
7247                         ip++;
7248
7249                         target = ip + 4 + (gint32)read32(ip);
7250                         ip += 4;
7251                         GET_BBLOCK (cfg, tblock, target);
7252                         link_bblock (cfg, bblock, tblock);
7253                         ins->inst_target_bb = tblock;
7254                         if (sp != stack_start) {
7255                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7256                                 sp = stack_start;
7257                                 CHECK_UNVERIFIABLE (cfg);
7258                         }
7259
7260                         MONO_ADD_INS (bblock, ins);
7261
7262                         start_new_bblock = 1;
7263                         inline_costs += BRANCH_COST;
7264                         break;
7265                 case CEE_BRFALSE_S:
7266                 case CEE_BRTRUE_S:
7267                 case CEE_BRFALSE:
7268                 case CEE_BRTRUE: {
7269                         MonoInst *cmp;
7270                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
7271                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
7272                         guint32 opsize = is_short ? 1 : 4;
7273
7274                         CHECK_OPSIZE (opsize);
7275                         CHECK_STACK (1);
7276                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
7277                                 UNVERIFIED;
7278                         ip ++;
7279                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
7280                         ip += opsize;
7281
7282                         sp--;
7283
7284                         GET_BBLOCK (cfg, tblock, target);
7285                         link_bblock (cfg, bblock, tblock);
7286                         GET_BBLOCK (cfg, tblock, ip);
7287                         link_bblock (cfg, bblock, tblock);
7288
7289                         if (sp != stack_start) {
7290                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7291                                 CHECK_UNVERIFIABLE (cfg);
7292                         }
7293
7294                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
7295                         cmp->sreg1 = sp [0]->dreg;
7296                         type_from_op (cmp, sp [0], NULL);
7297                         CHECK_TYPE (cmp);
7298
7299 #if SIZEOF_REGISTER == 4
7300                         if (cmp->opcode == OP_LCOMPARE_IMM) {
7301                                 /* Convert it to OP_LCOMPARE */
7302                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
7303                                 ins->type = STACK_I8;
7304                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
7305                                 ins->inst_l = 0;
7306                                 MONO_ADD_INS (bblock, ins);
7307                                 cmp->opcode = OP_LCOMPARE;
7308                                 cmp->sreg2 = ins->dreg;
7309                         }
7310 #endif
7311                         MONO_ADD_INS (bblock, cmp);
7312
7313                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
7314                         type_from_op (ins, sp [0], NULL);
7315                         MONO_ADD_INS (bblock, ins);
7316                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
7317                         GET_BBLOCK (cfg, tblock, target);
7318                         ins->inst_true_bb = tblock;
7319                         GET_BBLOCK (cfg, tblock, ip);
7320                         ins->inst_false_bb = tblock;
7321                         start_new_bblock = 2;
7322
7323                         sp = stack_start;
7324                         inline_costs += BRANCH_COST;
7325                         break;
7326                 }
7327                 case CEE_BEQ:
7328                 case CEE_BGE:
7329                 case CEE_BGT:
7330                 case CEE_BLE:
7331                 case CEE_BLT:
7332                 case CEE_BNE_UN:
7333                 case CEE_BGE_UN:
7334                 case CEE_BGT_UN:
7335                 case CEE_BLE_UN:
7336                 case CEE_BLT_UN:
7337                         CHECK_OPSIZE (5);
7338                         CHECK_STACK (2);
7339                         MONO_INST_NEW (cfg, ins, *ip);
7340                         ip++;
7341                         target = ip + 4 + (gint32)read32(ip);
7342                         ip += 4;
7343
7344                         ADD_BINCOND (NULL);
7345
7346                         sp = stack_start;
7347                         inline_costs += BRANCH_COST;
7348                         break;
7349                 case CEE_SWITCH: {
7350                         MonoInst *src1;
7351                         MonoBasicBlock **targets;
7352                         MonoBasicBlock *default_bblock;
7353                         MonoJumpInfoBBTable *table;
7354                         int offset_reg = alloc_preg (cfg);
7355                         int target_reg = alloc_preg (cfg);
7356                         int table_reg = alloc_preg (cfg);
7357                         int sum_reg = alloc_preg (cfg);
7358                         gboolean use_op_switch;
7359
7360                         CHECK_OPSIZE (5);
7361                         CHECK_STACK (1);
7362                         n = read32 (ip + 1);
7363                         --sp;
7364                         src1 = sp [0];
7365                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
7366                                 UNVERIFIED;
7367
7368                         ip += 5;
7369                         CHECK_OPSIZE (n * sizeof (guint32));
7370                         target = ip + n * sizeof (guint32);
7371
7372                         GET_BBLOCK (cfg, default_bblock, target);
7373                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7374
7375                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
7376                         for (i = 0; i < n; ++i) {
7377                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
7378                                 targets [i] = tblock;
7379                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
7380                                 ip += 4;
7381                         }
7382
7383                         if (sp != stack_start) {
7384                                 /* 
7385                                  * Link the current bb with the targets as well, so handle_stack_args
7386                                  * will set their in_stack correctly.
7387                                  */
7388                                 link_bblock (cfg, bblock, default_bblock);
7389                                 for (i = 0; i < n; ++i)
7390                                         link_bblock (cfg, bblock, targets [i]);
7391
7392                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7393                                 sp = stack_start;
7394                                 CHECK_UNVERIFIABLE (cfg);
7395                         }
7396
7397                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
7398                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
7399                         bblock = cfg->cbb;
7400
7401                         for (i = 0; i < n; ++i)
7402                                 link_bblock (cfg, bblock, targets [i]);
7403
7404                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
7405                         table->table = targets;
7406                         table->table_size = n;
7407
7408                         use_op_switch = FALSE;
7409 #ifdef TARGET_ARM
7410                         /* ARM implements SWITCH statements differently */
7411                         /* FIXME: Make it use the generic implementation */
7412                         if (!cfg->compile_aot)
7413                                 use_op_switch = TRUE;
7414 #endif
7415
7416                         if (COMPILE_LLVM (cfg))
7417                                 use_op_switch = TRUE;
7418
7419                         cfg->cbb->has_jump_table = 1;
7420
7421                         if (use_op_switch) {
7422                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
7423                                 ins->sreg1 = src1->dreg;
7424                                 ins->inst_p0 = table;
7425                                 ins->inst_many_bb = targets;
7426                                 ins->klass = GUINT_TO_POINTER (n);
7427                                 MONO_ADD_INS (cfg->cbb, ins);
7428                         } else {
7429                                 if (sizeof (gpointer) == 8)
7430                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
7431                                 else
7432                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
7433
7434 #if SIZEOF_REGISTER == 8
7435                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
7436                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
7437 #endif
7438
7439                                 if (cfg->compile_aot) {
7440                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
7441                                 } else {
7442                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
7443                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
7444                                         ins->inst_p0 = table;
7445                                         ins->dreg = table_reg;
7446                                         MONO_ADD_INS (cfg->cbb, ins);
7447                                 }
7448
7449                                 /* FIXME: Use load_memindex */
7450                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
7451                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
7452                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
7453                         }
7454                         start_new_bblock = 1;
7455                         inline_costs += (BRANCH_COST * 2);
7456                         break;
7457                 }
7458                 case CEE_LDIND_I1:
7459                 case CEE_LDIND_U1:
7460                 case CEE_LDIND_I2:
7461                 case CEE_LDIND_U2:
7462                 case CEE_LDIND_I4:
7463                 case CEE_LDIND_U4:
7464                 case CEE_LDIND_I8:
7465                 case CEE_LDIND_I:
7466                 case CEE_LDIND_R4:
7467                 case CEE_LDIND_R8:
7468                 case CEE_LDIND_REF:
7469                         CHECK_STACK (1);
7470                         --sp;
7471
7472                         switch (*ip) {
7473                         case CEE_LDIND_R4:
7474                         case CEE_LDIND_R8:
7475                                 dreg = alloc_freg (cfg);
7476                                 break;
7477                         case CEE_LDIND_I8:
7478                                 dreg = alloc_lreg (cfg);
7479                                 break;
7480                         default:
7481                                 dreg = alloc_preg (cfg);
7482                         }
7483
7484                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
7485                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
7486                         ins->flags |= ins_flag;
7487                         ins_flag = 0;
7488                         MONO_ADD_INS (bblock, ins);
7489                         *sp++ = ins;
7490                         ++ip;
7491                         break;
7492                 case CEE_STIND_REF:
7493                 case CEE_STIND_I1:
7494                 case CEE_STIND_I2:
7495                 case CEE_STIND_I4:
7496                 case CEE_STIND_I8:
7497                 case CEE_STIND_R4:
7498                 case CEE_STIND_R8:
7499                 case CEE_STIND_I:
7500                         CHECK_STACK (2);
7501                         sp -= 2;
7502
7503                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
7504                         ins->flags |= ins_flag;
7505                         ins_flag = 0;
7506                         MONO_ADD_INS (bblock, ins);
7507
7508                         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)))
7509                                 emit_write_barrier (cfg, sp [0], sp [1], -1);
7510
7511                         inline_costs += 1;
7512                         ++ip;
7513                         break;
7514
7515                 case CEE_MUL:
7516                         CHECK_STACK (2);
7517
7518                         MONO_INST_NEW (cfg, ins, (*ip));
7519                         sp -= 2;
7520                         ins->sreg1 = sp [0]->dreg;
7521                         ins->sreg2 = sp [1]->dreg;
7522                         type_from_op (ins, sp [0], sp [1]);
7523                         CHECK_TYPE (ins);
7524                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7525
7526                         /* Use the immediate opcodes if possible */
7527                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
7528                                 int imm_opcode = mono_op_to_op_imm (ins->opcode);
7529                                 if (imm_opcode != -1) {
7530                                         ins->opcode = imm_opcode;
7531                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
7532                                         ins->sreg2 = -1;
7533
7534                                         sp [1]->opcode = OP_NOP;
7535                                 }
7536                         }
7537
7538                         MONO_ADD_INS ((cfg)->cbb, (ins));
7539
7540                         *sp++ = mono_decompose_opcode (cfg, ins);
7541                         ip++;
7542                         break;
7543                 case CEE_ADD:
7544                 case CEE_SUB:
7545                 case CEE_DIV:
7546                 case CEE_DIV_UN:
7547                 case CEE_REM:
7548                 case CEE_REM_UN:
7549                 case CEE_AND:
7550                 case CEE_OR:
7551                 case CEE_XOR:
7552                 case CEE_SHL:
7553                 case CEE_SHR:
7554                 case CEE_SHR_UN:
7555                         CHECK_STACK (2);
7556
7557                         MONO_INST_NEW (cfg, ins, (*ip));
7558                         sp -= 2;
7559                         ins->sreg1 = sp [0]->dreg;
7560                         ins->sreg2 = sp [1]->dreg;
7561                         type_from_op (ins, sp [0], sp [1]);
7562                         CHECK_TYPE (ins);
7563                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
7564                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7565
7566                         /* FIXME: Pass opcode to is_inst_imm */
7567
7568                         /* Use the immediate opcodes if possible */
7569                         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)) {
7570                                 int imm_opcode;
7571
7572                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
7573                                 if (imm_opcode != -1) {
7574                                         ins->opcode = imm_opcode;
7575                                         if (sp [1]->opcode == OP_I8CONST) {
7576 #if SIZEOF_REGISTER == 8
7577                                                 ins->inst_imm = sp [1]->inst_l;
7578 #else
7579                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
7580                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
7581 #endif
7582                                         }
7583                                         else
7584                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
7585                                         ins->sreg2 = -1;
7586
7587                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
7588                                         if (sp [1]->next == NULL)
7589                                                 sp [1]->opcode = OP_NOP;
7590                                 }
7591                         }
7592                         MONO_ADD_INS ((cfg)->cbb, (ins));
7593
7594                         *sp++ = mono_decompose_opcode (cfg, ins);
7595                         ip++;
7596                         break;
7597                 case CEE_NEG:
7598                 case CEE_NOT:
7599                 case CEE_CONV_I1:
7600                 case CEE_CONV_I2:
7601                 case CEE_CONV_I4:
7602                 case CEE_CONV_R4:
7603                 case CEE_CONV_R8:
7604                 case CEE_CONV_U4:
7605                 case CEE_CONV_I8:
7606                 case CEE_CONV_U8:
7607                 case CEE_CONV_OVF_I8:
7608                 case CEE_CONV_OVF_U8:
7609                 case CEE_CONV_R_UN:
7610                         CHECK_STACK (1);
7611
7612                         /* Special case this earlier so we have long constants in the IR */
7613                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
7614                                 int data = sp [-1]->inst_c0;
7615                                 sp [-1]->opcode = OP_I8CONST;
7616                                 sp [-1]->type = STACK_I8;
7617 #if SIZEOF_REGISTER == 8
7618                                 if ((*ip) == CEE_CONV_U8)
7619                                         sp [-1]->inst_c0 = (guint32)data;
7620                                 else
7621                                         sp [-1]->inst_c0 = data;
7622 #else
7623                                 sp [-1]->inst_ls_word = data;
7624                                 if ((*ip) == CEE_CONV_U8)
7625                                         sp [-1]->inst_ms_word = 0;
7626                                 else
7627                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
7628 #endif
7629                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
7630                         }
7631                         else {
7632                                 ADD_UNOP (*ip);
7633                         }
7634                         ip++;
7635                         break;
7636                 case CEE_CONV_OVF_I4:
7637                 case CEE_CONV_OVF_I1:
7638                 case CEE_CONV_OVF_I2:
7639                 case CEE_CONV_OVF_I:
7640                 case CEE_CONV_OVF_U:
7641                         CHECK_STACK (1);
7642
7643                         if (sp [-1]->type == STACK_R8) {
7644                                 ADD_UNOP (CEE_CONV_OVF_I8);
7645                                 ADD_UNOP (*ip);
7646                         } else {
7647                                 ADD_UNOP (*ip);
7648                         }
7649                         ip++;
7650                         break;
7651                 case CEE_CONV_OVF_U1:
7652                 case CEE_CONV_OVF_U2:
7653                 case CEE_CONV_OVF_U4:
7654                         CHECK_STACK (1);
7655
7656                         if (sp [-1]->type == STACK_R8) {
7657                                 ADD_UNOP (CEE_CONV_OVF_U8);
7658                                 ADD_UNOP (*ip);
7659                         } else {
7660                                 ADD_UNOP (*ip);
7661                         }
7662                         ip++;
7663                         break;
7664                 case CEE_CONV_OVF_I1_UN:
7665                 case CEE_CONV_OVF_I2_UN:
7666                 case CEE_CONV_OVF_I4_UN:
7667                 case CEE_CONV_OVF_I8_UN:
7668                 case CEE_CONV_OVF_U1_UN:
7669                 case CEE_CONV_OVF_U2_UN:
7670                 case CEE_CONV_OVF_U4_UN:
7671                 case CEE_CONV_OVF_U8_UN:
7672                 case CEE_CONV_OVF_I_UN:
7673                 case CEE_CONV_OVF_U_UN:
7674                 case CEE_CONV_U2:
7675                 case CEE_CONV_U1:
7676                 case CEE_CONV_I:
7677                 case CEE_CONV_U:
7678                         CHECK_STACK (1);
7679                         ADD_UNOP (*ip);
7680                         CHECK_CFG_EXCEPTION;
7681                         ip++;
7682                         break;
7683                 case CEE_ADD_OVF:
7684                 case CEE_ADD_OVF_UN:
7685                 case CEE_MUL_OVF:
7686                 case CEE_MUL_OVF_UN:
7687                 case CEE_SUB_OVF:
7688                 case CEE_SUB_OVF_UN:
7689                         CHECK_STACK (2);
7690                         ADD_BINOP (*ip);
7691                         ip++;
7692                         break;
7693                 case CEE_CPOBJ:
7694                         CHECK_OPSIZE (5);
7695                         CHECK_STACK (2);
7696                         token = read32 (ip + 1);
7697                         klass = mini_get_class (method, token, generic_context);
7698                         CHECK_TYPELOAD (klass);
7699                         sp -= 2;
7700                         if (generic_class_is_reference_type (cfg, klass)) {
7701                                 MonoInst *store, *load;
7702                                 int dreg = alloc_preg (cfg);
7703
7704                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
7705                                 load->flags |= ins_flag;
7706                                 MONO_ADD_INS (cfg->cbb, load);
7707
7708                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
7709                                 store->flags |= ins_flag;
7710                                 MONO_ADD_INS (cfg->cbb, store);
7711
7712                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
7713                                         emit_write_barrier (cfg, sp [0], sp [1], -1);
7714                         } else {
7715                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7716                         }
7717                         ins_flag = 0;
7718                         ip += 5;
7719                         break;
7720                 case CEE_LDOBJ: {
7721                         int loc_index = -1;
7722                         int stloc_len = 0;
7723
7724                         CHECK_OPSIZE (5);
7725                         CHECK_STACK (1);
7726                         --sp;
7727                         token = read32 (ip + 1);
7728                         klass = mini_get_class (method, token, generic_context);
7729                         CHECK_TYPELOAD (klass);
7730
7731                         /* Optimize the common ldobj+stloc combination */
7732                         switch (ip [5]) {
7733                         case CEE_STLOC_S:
7734                                 loc_index = ip [6];
7735                                 stloc_len = 2;
7736                                 break;
7737                         case CEE_STLOC_0:
7738                         case CEE_STLOC_1:
7739                         case CEE_STLOC_2:
7740                         case CEE_STLOC_3:
7741                                 loc_index = ip [5] - CEE_STLOC_0;
7742                                 stloc_len = 1;
7743                                 break;
7744                         default:
7745                                 break;
7746                         }
7747
7748                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7749                                 CHECK_LOCAL (loc_index);
7750
7751                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7752                                 ins->dreg = cfg->locals [loc_index]->dreg;
7753                                 ip += 5;
7754                                 ip += stloc_len;
7755                                 break;
7756                         }
7757
7758                         /* Optimize the ldobj+stobj combination */
7759                         /* The reference case ends up being a load+store anyway */
7760                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
7761                                 CHECK_STACK (1);
7762
7763                                 sp --;
7764
7765                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7766
7767                                 ip += 5 + 5;
7768                                 ins_flag = 0;
7769                                 break;
7770                         }
7771
7772                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7773                         *sp++ = ins;
7774
7775                         ip += 5;
7776                         ins_flag = 0;
7777                         inline_costs += 1;
7778                         break;
7779                 }
7780                 case CEE_LDSTR:
7781                         CHECK_STACK_OVF (1);
7782                         CHECK_OPSIZE (5);
7783                         n = read32 (ip + 1);
7784
7785                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7786                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7787                                 ins->type = STACK_OBJ;
7788                                 *sp = ins;
7789                         }
7790                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7791                                 MonoInst *iargs [1];
7792
7793                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
7794                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
7795                         } else {
7796                                 if (cfg->opt & MONO_OPT_SHARED) {
7797                                         MonoInst *iargs [3];
7798
7799                                         if (cfg->compile_aot) {
7800                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7801                                         }
7802                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7803                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
7804                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7805                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
7806                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7807                                 } else {
7808                                         if (bblock->out_of_line) {
7809                                                 MonoInst *iargs [2];
7810
7811                                                 if (image == mono_defaults.corlib) {
7812                                                         /* 
7813                                                          * Avoid relocations in AOT and save some space by using a 
7814                                                          * version of helper_ldstr specialized to mscorlib.
7815                                                          */
7816                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7817                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
7818                                                 } else {
7819                                                         /* Avoid creating the string object */
7820                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
7821                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7822                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
7823                                                 }
7824                                         } 
7825                                         else
7826                                         if (cfg->compile_aot) {
7827                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7828                                                 *sp = ins;
7829                                                 MONO_ADD_INS (bblock, ins);
7830                                         } 
7831                                         else {
7832                                                 NEW_PCONST (cfg, ins, NULL);
7833                                                 ins->type = STACK_OBJ;
7834                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7835                                                 if (!ins->inst_p0)
7836                                                         OUT_OF_MEMORY_FAILURE;
7837
7838                                                 *sp = ins;
7839                                                 MONO_ADD_INS (bblock, ins);
7840                                         }
7841                                 }
7842                         }
7843
7844                         sp++;
7845                         ip += 5;
7846                         break;
7847                 case CEE_NEWOBJ: {
7848                         MonoInst *iargs [2];
7849                         MonoMethodSignature *fsig;
7850                         MonoInst this_ins;
7851                         MonoInst *alloc;
7852                         MonoInst *vtable_arg = NULL;
7853
7854                         CHECK_OPSIZE (5);
7855                         token = read32 (ip + 1);
7856                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7857                         if (!cmethod || mono_loader_get_last_error ())
7858                                 LOAD_ERROR;
7859                         fsig = mono_method_get_signature (cmethod, image, token);
7860                         if (!fsig)
7861                                 LOAD_ERROR;
7862
7863                         mono_save_token_info (cfg, image, token, cmethod);
7864
7865                         if (!mono_class_init (cmethod->klass))
7866                                 LOAD_ERROR;
7867
7868                         if (cfg->generic_sharing_context)
7869                                 context_used = mono_method_check_context_used (cmethod);
7870
7871                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7872                                 if (check_linkdemand (cfg, method, cmethod))
7873                                         INLINE_FAILURE;
7874                                 CHECK_CFG_EXCEPTION;
7875                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7876                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7877                         }
7878
7879                         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)) {
7880                                 emit_generic_class_init (cfg, cmethod->klass);
7881                                 CHECK_TYPELOAD (cmethod->klass);
7882                         }
7883
7884                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7885                                         mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
7886                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7887                                         mono_class_vtable (cfg->domain, cmethod->klass);
7888                                         CHECK_TYPELOAD (cmethod->klass);
7889
7890                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7891                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7892                                 } else {
7893                                         if (context_used) {
7894                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7895                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7896                                         } else {
7897                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7898
7899                                                 CHECK_TYPELOAD (cmethod->klass);
7900                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7901                                         }
7902                                 }
7903                         }
7904
7905                         n = fsig->param_count;
7906                         CHECK_STACK (n);
7907
7908                         /* 
7909                          * Generate smaller code for the common newobj <exception> instruction in
7910                          * argument checking code.
7911                          */
7912                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
7913                                 is_exception_class (cmethod->klass) && n <= 2 &&
7914                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7915                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7916                                 MonoInst *iargs [3];
7917
7918                                 g_assert (!vtable_arg);
7919
7920                                 sp -= n;
7921
7922                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7923                                 switch (n) {
7924                                 case 0:
7925                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
7926                                         break;
7927                                 case 1:
7928                                         iargs [1] = sp [0];
7929                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
7930                                         break;
7931                                 case 2:
7932                                         iargs [1] = sp [0];
7933                                         iargs [2] = sp [1];
7934                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
7935                                         break;
7936                                 default:
7937                                         g_assert_not_reached ();
7938                                 }
7939
7940                                 ip += 5;
7941                                 inline_costs += 5;
7942                                 break;
7943                         }
7944
7945                         /* move the args to allow room for 'this' in the first position */
7946                         while (n--) {
7947                                 --sp;
7948                                 sp [1] = sp [0];
7949                         }
7950
7951                         /* check_call_signature () requires sp[0] to be set */
7952                         this_ins.type = STACK_OBJ;
7953                         sp [0] = &this_ins;
7954                         if (check_call_signature (cfg, fsig, sp))
7955                                 UNVERIFIED;
7956
7957                         iargs [0] = NULL;
7958
7959                         if (mini_class_is_system_array (cmethod->klass)) {
7960                                 g_assert (!vtable_arg);
7961
7962                                 *sp = emit_get_rgctx_method (cfg, context_used,
7963                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
7964
7965                                 /* Avoid varargs in the common case */
7966                                 if (fsig->param_count == 1)
7967                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
7968                                 else if (fsig->param_count == 2)
7969                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
7970                                 else if (fsig->param_count == 3)
7971                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
7972                                 else
7973                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
7974                         } else if (cmethod->string_ctor) {
7975                                 g_assert (!context_used);
7976                                 g_assert (!vtable_arg);
7977                                 /* we simply pass a null pointer */
7978                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
7979                                 /* now call the string ctor */
7980                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL);
7981                         } else {
7982                                 MonoInst* callvirt_this_arg = NULL;
7983                                 
7984                                 if (cmethod->klass->valuetype) {
7985                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7986                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
7987                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
7988
7989                                         alloc = NULL;
7990
7991                                         /* 
7992                                          * The code generated by mini_emit_virtual_call () expects
7993                                          * iargs [0] to be a boxed instance, but luckily the vcall
7994                                          * will be transformed into a normal call there.
7995                                          */
7996                                 } else if (context_used) {
7997                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
7998                                         *sp = alloc;
7999                                 } else {
8000                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8001
8002                                         CHECK_TYPELOAD (cmethod->klass);
8003
8004                                         /*
8005                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
8006                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
8007                                          * As a workaround, we call class cctors before allocating objects.
8008                                          */
8009                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8010                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
8011                                                 if (cfg->verbose_level > 2)
8012                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
8013                                                 class_inits = g_slist_prepend (class_inits, vtable);
8014                                         }
8015
8016                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
8017                                         *sp = alloc;
8018                                 }
8019                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
8020
8021                                 if (alloc)
8022                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
8023
8024                                 /* Now call the actual ctor */
8025                                 /* Avoid virtual calls to ctors if possible */
8026                                 if (cmethod->klass->marshalbyref)
8027                                         callvirt_this_arg = sp [0];
8028
8029
8030                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
8031                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8032                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
8033                                                 *sp = ins;
8034                                                 sp++;
8035                                         }
8036
8037                                         CHECK_CFG_EXCEPTION;
8038                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
8039                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
8040                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
8041                                     !g_list_find (dont_inline, cmethod)) {
8042                                         int costs;
8043
8044                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
8045                                                 cfg->real_offset += 5;
8046                                                 bblock = cfg->cbb;
8047
8048                                                 inline_costs += costs - 5;
8049                                         } else {
8050                                                 INLINE_FAILURE;
8051                                                 mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
8052                                         }
8053                                 } else if (context_used &&
8054                                                 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
8055                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
8056                                         MonoInst *cmethod_addr;
8057
8058                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
8059                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8060
8061                                         mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
8062                                 } else {
8063                                         INLINE_FAILURE;
8064                                         ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
8065                                                                                                                         callvirt_this_arg, NULL, vtable_arg);
8066                                 }
8067                         }
8068
8069                         if (alloc == NULL) {
8070                                 /* Valuetype */
8071                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
8072                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
8073                                 *sp++= ins;
8074                         }
8075                         else
8076                                 *sp++ = alloc;
8077                         
8078                         ip += 5;
8079                         inline_costs += 5;
8080                         break;
8081                 }
8082                 case CEE_CASTCLASS:
8083                         CHECK_STACK (1);
8084                         --sp;
8085                         CHECK_OPSIZE (5);
8086                         token = read32 (ip + 1);
8087                         klass = mini_get_class (method, token, generic_context);
8088                         CHECK_TYPELOAD (klass);
8089                         if (sp [0]->type != STACK_OBJ)
8090                                 UNVERIFIED;
8091
8092                         if (cfg->generic_sharing_context)
8093                                 context_used = mono_class_check_context_used (klass);
8094
8095                         if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8096                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
8097                                 MonoInst *args [3];
8098
8099                                 /* obj */
8100                                 args [0] = *sp;
8101
8102                                 /* klass */
8103                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8104
8105                                 /* inline cache*/
8106                                 /*FIXME AOT support*/
8107                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8108
8109                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
8110                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
8111                                 ip += 5;
8112                                 inline_costs += 2;
8113                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8114                                 MonoMethod *mono_castclass;
8115                                 MonoInst *iargs [1];
8116                                 int costs;
8117
8118                                 mono_castclass = mono_marshal_get_castclass (klass); 
8119                                 iargs [0] = sp [0];
8120                                 
8121                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
8122                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
8123                                 CHECK_CFG_EXCEPTION;
8124                                 g_assert (costs > 0);
8125                                 
8126                                 ip += 5;
8127                                 cfg->real_offset += 5;
8128                                 bblock = cfg->cbb;
8129
8130                                 *sp++ = iargs [0];
8131
8132                                 inline_costs += costs;
8133                         }
8134                         else {
8135                                 ins = handle_castclass (cfg, klass, *sp, context_used);
8136                                 CHECK_CFG_EXCEPTION;
8137                                 bblock = cfg->cbb;
8138                                 *sp ++ = ins;
8139                                 ip += 5;
8140                         }
8141                         break;
8142                 case CEE_ISINST: {
8143                         CHECK_STACK (1);
8144                         --sp;
8145                         CHECK_OPSIZE (5);
8146                         token = read32 (ip + 1);
8147                         klass = mini_get_class (method, token, generic_context);
8148                         CHECK_TYPELOAD (klass);
8149                         if (sp [0]->type != STACK_OBJ)
8150                                 UNVERIFIED;
8151  
8152                         if (cfg->generic_sharing_context)
8153                                 context_used = mono_class_check_context_used (klass);
8154
8155                         if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8156                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
8157                                 MonoInst *args [3];
8158
8159                                 /* obj */
8160                                 args [0] = *sp;
8161
8162                                 /* klass */
8163                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8164
8165                                 /* inline cache*/
8166                                 /*FIXME AOT support*/
8167                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8168
8169                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
8170                                 ip += 5;
8171                                 inline_costs += 2;
8172                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8173                                 MonoMethod *mono_isinst;
8174                                 MonoInst *iargs [1];
8175                                 int costs;
8176
8177                                 mono_isinst = mono_marshal_get_isinst (klass); 
8178                                 iargs [0] = sp [0];
8179
8180                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
8181                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
8182                                 CHECK_CFG_EXCEPTION;
8183                                 g_assert (costs > 0);
8184                                 
8185                                 ip += 5;
8186                                 cfg->real_offset += 5;
8187                                 bblock = cfg->cbb;
8188
8189                                 *sp++= iargs [0];
8190
8191                                 inline_costs += costs;
8192                         }
8193                         else {
8194                                 ins = handle_isinst (cfg, klass, *sp, context_used);
8195                                 CHECK_CFG_EXCEPTION;
8196                                 bblock = cfg->cbb;
8197                                 *sp ++ = ins;
8198                                 ip += 5;
8199                         }
8200                         break;
8201                 }
8202                 case CEE_UNBOX_ANY: {
8203                         CHECK_STACK (1);
8204                         --sp;
8205                         CHECK_OPSIZE (5);
8206                         token = read32 (ip + 1);
8207                         klass = mini_get_class (method, token, generic_context);
8208                         CHECK_TYPELOAD (klass);
8209  
8210                         mono_save_token_info (cfg, image, token, klass);
8211
8212                         if (cfg->generic_sharing_context)
8213                                 context_used = mono_class_check_context_used (klass);
8214
8215                         if (generic_class_is_reference_type (cfg, klass)) {
8216                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
8217                                 if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8218                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
8219                                         MonoInst *args [3];
8220
8221                                         /* obj */
8222                                         args [0] = *sp;
8223
8224                                         /* klass */
8225                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8226
8227                                         /* inline cache*/
8228                                         /*FIXME AOT support*/
8229                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8230
8231                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
8232                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
8233                                         ip += 5;
8234                                         inline_costs += 2;
8235                                 } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8236                                         MonoMethod *mono_castclass;
8237                                         MonoInst *iargs [1];
8238                                         int costs;
8239
8240                                         mono_castclass = mono_marshal_get_castclass (klass); 
8241                                         iargs [0] = sp [0];
8242
8243                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
8244                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8245                                         CHECK_CFG_EXCEPTION;
8246                                         g_assert (costs > 0);
8247                                 
8248                                         ip += 5;
8249                                         cfg->real_offset += 5;
8250                                         bblock = cfg->cbb;
8251
8252                                         *sp++ = iargs [0];
8253                                         inline_costs += costs;
8254                                 } else {
8255                                         ins = handle_castclass (cfg, klass, *sp, context_used);
8256                                         CHECK_CFG_EXCEPTION;
8257                                         bblock = cfg->cbb;
8258                                         *sp ++ = ins;
8259                                         ip += 5;
8260                                 }
8261                                 break;
8262                         }
8263
8264                         if (mono_class_is_nullable (klass)) {
8265                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
8266                                 *sp++= ins;
8267                                 ip += 5;
8268                                 break;
8269                         }
8270
8271                         /* UNBOX */
8272                         ins = handle_unbox (cfg, klass, sp, context_used);
8273                         *sp = ins;
8274
8275                         ip += 5;
8276
8277                         /* LDOBJ */
8278                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
8279                         *sp++ = ins;
8280
8281                         inline_costs += 2;
8282                         break;
8283                 }
8284                 case CEE_BOX: {
8285                         MonoInst *val;
8286
8287                         CHECK_STACK (1);
8288                         --sp;
8289                         val = *sp;
8290                         CHECK_OPSIZE (5);
8291                         token = read32 (ip + 1);
8292                         klass = mini_get_class (method, token, generic_context);
8293                         CHECK_TYPELOAD (klass);
8294
8295                         mono_save_token_info (cfg, image, token, klass);
8296
8297                         if (cfg->generic_sharing_context)
8298                                 context_used = mono_class_check_context_used (klass);
8299
8300                         if (generic_class_is_reference_type (cfg, klass)) {
8301                                 *sp++ = val;
8302                                 ip += 5;
8303                                 break;
8304                         }
8305
8306                         if (klass == mono_defaults.void_class)
8307                                 UNVERIFIED;
8308                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8309                                 UNVERIFIED;
8310                         /* frequent check in generic code: box (struct), brtrue */
8311
8312                         // FIXME: LLVM can't handle the inconsistent bb linking
8313                         if (!mono_class_is_nullable (klass) &&
8314                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
8315                                 (ip [5] == CEE_BRTRUE || 
8316                                  ip [5] == CEE_BRTRUE_S ||
8317                                  ip [5] == CEE_BRFALSE ||
8318                                  ip [5] == CEE_BRFALSE_S)) {
8319                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
8320                                 int dreg;
8321                                 MonoBasicBlock *true_bb, *false_bb;
8322
8323                                 ip += 5;
8324
8325                                 if (cfg->verbose_level > 3) {
8326                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8327                                         printf ("<box+brtrue opt>\n");
8328                                 }
8329
8330                                 switch (*ip) {
8331                                 case CEE_BRTRUE_S:
8332                                 case CEE_BRFALSE_S:
8333                                         CHECK_OPSIZE (2);
8334                                         ip++;
8335                                         target = ip + 1 + (signed char)(*ip);
8336                                         ip++;
8337                                         break;
8338                                 case CEE_BRTRUE:
8339                                 case CEE_BRFALSE:
8340                                         CHECK_OPSIZE (5);
8341                                         ip++;
8342                                         target = ip + 4 + (gint)(read32 (ip));
8343                                         ip += 4;
8344                                         break;
8345                                 default:
8346                                         g_assert_not_reached ();
8347                                 }
8348
8349                                 /* 
8350                                  * We need to link both bblocks, since it is needed for handling stack
8351                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
8352                                  * Branching to only one of them would lead to inconsistencies, so
8353                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
8354                                  */
8355                                 GET_BBLOCK (cfg, true_bb, target);
8356                                 GET_BBLOCK (cfg, false_bb, ip);
8357
8358                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
8359                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
8360
8361                                 if (sp != stack_start) {
8362                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8363                                         sp = stack_start;
8364                                         CHECK_UNVERIFIABLE (cfg);
8365                                 }
8366
8367                                 if (COMPILE_LLVM (cfg)) {
8368                                         dreg = alloc_ireg (cfg);
8369                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
8370                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
8371
8372                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
8373                                 } else {
8374                                         /* The JIT can't eliminate the iconst+compare */
8375                                         MONO_INST_NEW (cfg, ins, OP_BR);
8376                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
8377                                         MONO_ADD_INS (cfg->cbb, ins);
8378                                 }
8379
8380                                 start_new_bblock = 1;
8381                                 break;
8382                         }
8383
8384                         *sp++ = handle_box (cfg, val, klass, context_used);
8385
8386                         CHECK_CFG_EXCEPTION;
8387                         ip += 5;
8388                         inline_costs += 1;
8389                         break;
8390                 }
8391                 case CEE_UNBOX: {
8392                         CHECK_STACK (1);
8393                         --sp;
8394                         CHECK_OPSIZE (5);
8395                         token = read32 (ip + 1);
8396                         klass = mini_get_class (method, token, generic_context);
8397                         CHECK_TYPELOAD (klass);
8398
8399                         mono_save_token_info (cfg, image, token, klass);
8400
8401                         if (cfg->generic_sharing_context)
8402                                 context_used = mono_class_check_context_used (klass);
8403
8404                         if (mono_class_is_nullable (klass)) {
8405                                 MonoInst *val;
8406
8407                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
8408                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
8409
8410                                 *sp++= ins;
8411                         } else {
8412                                 ins = handle_unbox (cfg, klass, sp, context_used);
8413                                 *sp++ = ins;
8414                         }
8415                         ip += 5;
8416                         inline_costs += 2;
8417                         break;
8418                 }
8419                 case CEE_LDFLD:
8420                 case CEE_LDFLDA:
8421                 case CEE_STFLD: {
8422                         MonoClassField *field;
8423                         int costs;
8424                         guint foffset;
8425
8426                         if (*ip == CEE_STFLD) {
8427                                 CHECK_STACK (2);
8428                                 sp -= 2;
8429                         } else {
8430                                 CHECK_STACK (1);
8431                                 --sp;
8432                         }
8433                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
8434                                 UNVERIFIED;
8435                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
8436                                 UNVERIFIED;
8437                         CHECK_OPSIZE (5);
8438                         token = read32 (ip + 1);
8439                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8440                                 field = mono_method_get_wrapper_data (method, token);
8441                                 klass = field->parent;
8442                         }
8443                         else {
8444                                 field = mono_field_from_token (image, token, &klass, generic_context);
8445                         }
8446                         if (!field)
8447                                 LOAD_ERROR;
8448                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8449                                 FIELD_ACCESS_FAILURE;
8450                         mono_class_init (klass);
8451
8452                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
8453                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
8454                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8455                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8456                         */
8457
8458                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
8459                         if (*ip == CEE_STFLD) {
8460                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
8461                                         UNVERIFIED;
8462                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8463                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
8464                                         MonoInst *iargs [5];
8465
8466                                         iargs [0] = sp [0];
8467                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8468                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8469                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
8470                                                     field->offset);
8471                                         iargs [4] = sp [1];
8472
8473                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8474                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
8475                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
8476                                                 CHECK_CFG_EXCEPTION;
8477                                                 g_assert (costs > 0);
8478                                                       
8479                                                 cfg->real_offset += 5;
8480                                                 bblock = cfg->cbb;
8481
8482                                                 inline_costs += costs;
8483                                         } else {
8484                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
8485                                         }
8486                                 } else {
8487                                         MonoInst *store;
8488
8489                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8490
8491                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
8492                                         if (sp [0]->opcode != OP_LDADDR)
8493                                                 store->flags |= MONO_INST_FAULT;
8494
8495                                 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)) {
8496                                         /* insert call to write barrier */
8497                                         MonoInst *ptr;
8498                                         int dreg;
8499
8500                                         dreg = alloc_preg (cfg);
8501                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8502                                         emit_write_barrier (cfg, ptr, sp [1], -1);
8503                                 }
8504
8505                                         store->flags |= ins_flag;
8506                                 }
8507                                 ins_flag = 0;
8508                                 ip += 5;
8509                                 break;
8510                         }
8511
8512                         if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8513                                 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
8514                                 MonoInst *iargs [4];
8515
8516                                 iargs [0] = sp [0];
8517                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8518                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8519                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
8520                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8521                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
8522                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8523                                         CHECK_CFG_EXCEPTION;
8524                                         bblock = cfg->cbb;
8525                                         g_assert (costs > 0);
8526                                                       
8527                                         cfg->real_offset += 5;
8528
8529                                         *sp++ = iargs [0];
8530
8531                                         inline_costs += costs;
8532                                 } else {
8533                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
8534                                         *sp++ = ins;
8535                                 }
8536                         } else {
8537                                 if (sp [0]->type == STACK_VTYPE) {
8538                                         MonoInst *var;
8539
8540                                         /* Have to compute the address of the variable */
8541
8542                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
8543                                         if (!var)
8544                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
8545                                         else
8546                                                 g_assert (var->klass == klass);
8547                                         
8548                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
8549                                         sp [0] = ins;
8550                                 }
8551
8552                                 if (*ip == CEE_LDFLDA) {
8553                                         if (sp [0]->type == STACK_OBJ) {
8554                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
8555                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
8556                                         }
8557
8558                                         dreg = alloc_preg (cfg);
8559
8560                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8561                                         ins->klass = mono_class_from_mono_type (field->type);
8562                                         ins->type = STACK_MP;
8563                                         *sp++ = ins;
8564                                 } else {
8565                                         MonoInst *load;
8566
8567                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8568
8569                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
8570                                         load->flags |= ins_flag;
8571                                         if (sp [0]->opcode != OP_LDADDR)
8572                                                 load->flags |= MONO_INST_FAULT;
8573                                         *sp++ = load;
8574                                 }
8575                         }
8576                         ins_flag = 0;
8577                         ip += 5;
8578                         break;
8579                 }
8580                 case CEE_LDSFLD:
8581                 case CEE_LDSFLDA:
8582                 case CEE_STSFLD: {
8583                         MonoClassField *field;
8584                         gpointer addr = NULL;
8585                         gboolean is_special_static;
8586                         MonoType *ftype;
8587
8588                         CHECK_OPSIZE (5);
8589                         token = read32 (ip + 1);
8590
8591                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8592                                 field = mono_method_get_wrapper_data (method, token);
8593                                 klass = field->parent;
8594                         }
8595                         else
8596                                 field = mono_field_from_token (image, token, &klass, generic_context);
8597                         if (!field)
8598                                 LOAD_ERROR;
8599                         mono_class_init (klass);
8600                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8601                                 FIELD_ACCESS_FAILURE;
8602
8603                         /* if the class is Critical then transparent code cannot access it's fields */
8604                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8605                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8606
8607                         /*
8608                          * We can only support shared generic static
8609                          * field access on architectures where the
8610                          * trampoline code has been extended to handle
8611                          * the generic class init.
8612                          */
8613 #ifndef MONO_ARCH_VTABLE_REG
8614                         GENERIC_SHARING_FAILURE (*ip);
8615 #endif
8616
8617                         if (cfg->generic_sharing_context)
8618                                 context_used = mono_class_check_context_used (klass);
8619
8620                         ftype = mono_field_get_type (field);
8621
8622                         g_assert (!(ftype->attrs & FIELD_ATTRIBUTE_LITERAL));
8623
8624                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
8625                          * to be called here.
8626                          */
8627                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
8628                                 mono_class_vtable (cfg->domain, klass);
8629                                 CHECK_TYPELOAD (klass);
8630                         }
8631                         mono_domain_lock (cfg->domain);
8632                         if (cfg->domain->special_static_fields)
8633                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8634                         mono_domain_unlock (cfg->domain);
8635
8636                         is_special_static = mono_class_field_is_special_static (field);
8637
8638                         /* Generate IR to compute the field address */
8639                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
8640                                 /*
8641                                  * Fast access to TLS data
8642                                  * Inline version of get_thread_static_data () in
8643                                  * threads.c.
8644                                  */
8645                                 guint32 offset;
8646                                 int idx, static_data_reg, array_reg, dreg;
8647                                 MonoInst *thread_ins;
8648
8649                                 // offset &= 0x7fffffff;
8650                                 // idx = (offset >> 24) - 1;
8651                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
8652
8653                                 thread_ins = mono_get_thread_intrinsic (cfg);
8654                                 MONO_ADD_INS (cfg->cbb, thread_ins);
8655                                 static_data_reg = alloc_ireg (cfg);
8656                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
8657
8658                                 if (cfg->compile_aot) {
8659                                         int offset_reg, offset2_reg, idx_reg;
8660
8661                                         /* For TLS variables, this will return the TLS offset */
8662                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
8663                                         offset_reg = ins->dreg;
8664                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
8665                                         idx_reg = alloc_ireg (cfg);
8666                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
8667                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
8668                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
8669                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
8670                                         array_reg = alloc_ireg (cfg);
8671                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
8672                                         offset2_reg = alloc_ireg (cfg);
8673                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
8674                                         dreg = alloc_ireg (cfg);
8675                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
8676                                 } else {
8677                                         offset = (gsize)addr & 0x7fffffff;
8678                                         idx = (offset >> 24) - 1;
8679
8680                                         array_reg = alloc_ireg (cfg);
8681                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
8682                                         dreg = alloc_ireg (cfg);
8683                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
8684                                 }
8685                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
8686                                         (cfg->compile_aot && is_special_static) ||
8687                                         (context_used && is_special_static)) {
8688                                 MonoInst *iargs [2];
8689
8690                                 g_assert (field->parent);
8691                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8692                                 if (context_used) {
8693                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
8694                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
8695                                 } else {
8696                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8697                                 }
8698                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8699                         } else if (context_used) {
8700                                 MonoInst *static_data;
8701
8702                                 /*
8703                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8704                                         method->klass->name_space, method->klass->name, method->name,
8705                                         depth, field->offset);
8706                                 */
8707
8708                                 if (mono_class_needs_cctor_run (klass, method))
8709                                         emit_generic_class_init (cfg, klass);
8710
8711                                 /*
8712                                  * The pointer we're computing here is
8713                                  *
8714                                  *   super_info.static_data + field->offset
8715                                  */
8716                                 static_data = emit_get_rgctx_klass (cfg, context_used,
8717                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
8718
8719                                 if (field->offset == 0) {
8720                                         ins = static_data;
8721                                 } else {
8722                                         int addr_reg = mono_alloc_preg (cfg);
8723                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
8724                                 }
8725                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
8726                                 MonoInst *iargs [2];
8727
8728                                 g_assert (field->parent);
8729                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8730                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8731                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8732                         } else {
8733                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
8734
8735                                 CHECK_TYPELOAD (klass);
8736                                 if (!addr) {
8737                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8738                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
8739                                                 if (cfg->verbose_level > 2)
8740                                                         printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
8741                                                 class_inits = g_slist_prepend (class_inits, vtable);
8742                                         } else {
8743                                                 if (cfg->run_cctors) {
8744                                                         MonoException *ex;
8745                                                         /* This makes so that inline cannot trigger */
8746                                                         /* .cctors: too many apps depend on them */
8747                                                         /* running with a specific order... */
8748                                                         if (! vtable->initialized)
8749                                                                 INLINE_FAILURE;
8750                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8751                                                         if (ex) {
8752                                                                 set_exception_object (cfg, ex);
8753                                                                 goto exception_exit;
8754                                                         }
8755                                                 }
8756                                         }
8757                                         addr = (char*)vtable->data + field->offset;
8758
8759                                         if (cfg->compile_aot)
8760                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
8761                                         else
8762                                                 EMIT_NEW_PCONST (cfg, ins, addr);
8763                                 } else {
8764                                         MonoInst *iargs [1];
8765                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8766                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
8767                                 }
8768                         }
8769
8770                         /* Generate IR to do the actual load/store operation */
8771
8772                         if (*ip == CEE_LDSFLDA) {
8773                                 ins->klass = mono_class_from_mono_type (ftype);
8774                                 ins->type = STACK_PTR;
8775                                 *sp++ = ins;
8776                         } else if (*ip == CEE_STSFLD) {
8777                                 MonoInst *store;
8778                                 CHECK_STACK (1);
8779                                 sp--;
8780
8781                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, sp [0]->dreg);
8782                                 store->flags |= ins_flag;
8783                         } else {
8784                                 gboolean is_const = FALSE;
8785                                 MonoVTable *vtable = NULL;
8786
8787                                 if (!context_used) {
8788                                         vtable = mono_class_vtable (cfg->domain, klass);
8789                                         CHECK_TYPELOAD (klass);
8790                                 }
8791                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8792                                     vtable->initialized && (ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8793                                         gpointer addr = (char*)vtable->data + field->offset;
8794                                         int ro_type = ftype->type;
8795                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
8796                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
8797                                         }
8798                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
8799                                         is_const = TRUE;
8800                                         switch (ro_type) {
8801                                         case MONO_TYPE_BOOLEAN:
8802                                         case MONO_TYPE_U1:
8803                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8804                                                 sp++;
8805                                                 break;
8806                                         case MONO_TYPE_I1:
8807                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8808                                                 sp++;
8809                                                 break;                                          
8810                                         case MONO_TYPE_CHAR:
8811                                         case MONO_TYPE_U2:
8812                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8813                                                 sp++;
8814                                                 break;
8815                                         case MONO_TYPE_I2:
8816                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8817                                                 sp++;
8818                                                 break;
8819                                                 break;
8820                                         case MONO_TYPE_I4:
8821                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8822                                                 sp++;
8823                                                 break;                                          
8824                                         case MONO_TYPE_U4:
8825                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8826                                                 sp++;
8827                                                 break;
8828                                         case MONO_TYPE_I:
8829                                         case MONO_TYPE_U:
8830                                         case MONO_TYPE_PTR:
8831                                         case MONO_TYPE_FNPTR:
8832                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8833                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
8834                                                 sp++;
8835                                                 break;
8836                                         case MONO_TYPE_STRING:
8837                                         case MONO_TYPE_OBJECT:
8838                                         case MONO_TYPE_CLASS:
8839                                         case MONO_TYPE_SZARRAY:
8840                                         case MONO_TYPE_ARRAY:
8841                                                 if (!mono_gc_is_moving ()) {
8842                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8843                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
8844                                                         sp++;
8845                                                 } else {
8846                                                         is_const = FALSE;
8847                                                 }
8848                                                 break;
8849                                         case MONO_TYPE_I8:
8850                                         case MONO_TYPE_U8:
8851                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
8852                                                 sp++;
8853                                                 break;
8854                                         case MONO_TYPE_R4:
8855                                         case MONO_TYPE_R8:
8856                                         case MONO_TYPE_VALUETYPE:
8857                                         default:
8858                                                 is_const = FALSE;
8859                                                 break;
8860                                         }
8861                                 }
8862
8863                                 if (!is_const) {
8864                                         MonoInst *load;
8865
8866                                         CHECK_STACK_OVF (1);
8867
8868                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
8869                                         load->flags |= ins_flag;
8870                                         ins_flag = 0;
8871                                         *sp++ = load;
8872                                 }
8873                         }
8874                         ins_flag = 0;
8875                         ip += 5;
8876                         break;
8877                 }
8878                 case CEE_STOBJ:
8879                         CHECK_STACK (2);
8880                         sp -= 2;
8881                         CHECK_OPSIZE (5);
8882                         token = read32 (ip + 1);
8883                         klass = mini_get_class (method, token, generic_context);
8884                         CHECK_TYPELOAD (klass);
8885                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8886                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
8887                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
8888                                         generic_class_is_reference_type (cfg, klass)) {
8889                                 /* insert call to write barrier */
8890                                 emit_write_barrier (cfg, sp [0], sp [1], -1);
8891                         }
8892                         ins_flag = 0;
8893                         ip += 5;
8894                         inline_costs += 1;
8895                         break;
8896
8897                         /*
8898                          * Array opcodes
8899                          */
8900                 case CEE_NEWARR: {
8901                         MonoInst *len_ins;
8902                         const char *data_ptr;
8903                         int data_size = 0;
8904                         guint32 field_token;
8905
8906                         CHECK_STACK (1);
8907                         --sp;
8908
8909                         CHECK_OPSIZE (5);
8910                         token = read32 (ip + 1);
8911
8912                         klass = mini_get_class (method, token, generic_context);
8913                         CHECK_TYPELOAD (klass);
8914
8915                         if (cfg->generic_sharing_context)
8916                                 context_used = mono_class_check_context_used (klass);
8917
8918                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
8919                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
8920                                 ins->sreg1 = sp [0]->dreg;
8921                                 ins->type = STACK_I4;
8922                                 ins->dreg = alloc_ireg (cfg);
8923                                 MONO_ADD_INS (cfg->cbb, ins);
8924                                 *sp = mono_decompose_opcode (cfg, ins);
8925                         }
8926
8927                         if (context_used) {
8928                                 MonoInst *args [3];
8929                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8930                                 /* FIXME: we cannot get a managed
8931                                    allocator because we can't get the
8932                                    open generic class's vtable.  We
8933                                    have the same problem in
8934                                    handle_alloc().  This
8935                                    needs to be solved so that we can
8936                                    have managed allocs of shared
8937                                    generic classes. */
8938                                 /*
8939                                 MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
8940                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
8941                                 */
8942                                 MonoMethod *managed_alloc = NULL;
8943
8944                                 /* FIXME: Decompose later to help abcrem */
8945
8946                                 /* vtable */
8947                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
8948                                         array_class, MONO_RGCTX_INFO_VTABLE);
8949                                 /* array len */
8950                                 args [1] = sp [0];
8951
8952                                 if (managed_alloc)
8953                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
8954                                 else
8955                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
8956                         } else {
8957                                 if (cfg->opt & MONO_OPT_SHARED) {
8958                                         /* Decompose now to avoid problems with references to the domainvar */
8959                                         MonoInst *iargs [3];
8960
8961                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8962                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8963                                         iargs [2] = sp [0];
8964
8965                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
8966                                 } else {
8967                                         /* Decompose later since it is needed by abcrem */
8968                                         MonoClass *array_type = mono_array_class_get (klass, 1);
8969                                         mono_class_vtable (cfg->domain, array_type);
8970                                         CHECK_TYPELOAD (array_type);
8971
8972                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
8973                                         ins->dreg = alloc_preg (cfg);
8974                                         ins->sreg1 = sp [0]->dreg;
8975                                         ins->inst_newa_class = klass;
8976                                         ins->type = STACK_OBJ;
8977                                         ins->klass = klass;
8978                                         MONO_ADD_INS (cfg->cbb, ins);
8979                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8980                                         cfg->cbb->has_array_access = TRUE;
8981
8982                                         /* Needed so mono_emit_load_get_addr () gets called */
8983                                         mono_get_got_var (cfg);
8984                                 }
8985                         }
8986
8987                         len_ins = sp [0];
8988                         ip += 5;
8989                         *sp++ = ins;
8990                         inline_costs += 1;
8991
8992                         /* 
8993                          * we inline/optimize the initialization sequence if possible.
8994                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8995                          * for small sizes open code the memcpy
8996                          * ensure the rva field is big enough
8997                          */
8998                         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))) {
8999                                 MonoMethod *memcpy_method = get_memcpy_method ();
9000                                 MonoInst *iargs [3];
9001                                 int add_reg = alloc_preg (cfg);
9002
9003                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
9004                                 if (cfg->compile_aot) {
9005                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
9006                                 } else {
9007                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
9008                                 }
9009                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
9010                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
9011                                 ip += 11;
9012                         }
9013
9014                         break;
9015                 }
9016                 case CEE_LDLEN:
9017                         CHECK_STACK (1);
9018                         --sp;
9019                         if (sp [0]->type != STACK_OBJ)
9020                                 UNVERIFIED;
9021
9022                         dreg = alloc_preg (cfg);
9023                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
9024                         ins->dreg = alloc_preg (cfg);
9025                         ins->sreg1 = sp [0]->dreg;
9026                         ins->type = STACK_I4;
9027                         /* This flag will be inherited by the decomposition */
9028                         ins->flags |= MONO_INST_FAULT;
9029                         MONO_ADD_INS (cfg->cbb, ins);
9030                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
9031                         cfg->cbb->has_array_access = TRUE;
9032                         ip ++;
9033                         *sp++ = ins;
9034                         break;
9035                 case CEE_LDELEMA:
9036                         CHECK_STACK (2);
9037                         sp -= 2;
9038                         CHECK_OPSIZE (5);
9039                         if (sp [0]->type != STACK_OBJ)
9040                                 UNVERIFIED;
9041
9042                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
9043
9044                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
9045                         CHECK_TYPELOAD (klass);
9046                         /* we need to make sure that this array is exactly the type it needs
9047                          * to be for correctness. the wrappers are lax with their usage
9048                          * so we need to ignore them here
9049                          */
9050                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
9051                                 MonoClass *array_class = mono_array_class_get (klass, 1);
9052                                 mini_emit_check_array_type (cfg, sp [0], array_class);
9053                                 CHECK_TYPELOAD (array_class);
9054                         }
9055
9056                         readonly = FALSE;
9057                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
9058                         *sp++ = ins;
9059                         ip += 5;
9060                         break;
9061                 case CEE_LDELEM:
9062                 case CEE_LDELEM_I1:
9063                 case CEE_LDELEM_U1:
9064                 case CEE_LDELEM_I2:
9065                 case CEE_LDELEM_U2:
9066                 case CEE_LDELEM_I4:
9067                 case CEE_LDELEM_U4:
9068                 case CEE_LDELEM_I8:
9069                 case CEE_LDELEM_I:
9070                 case CEE_LDELEM_R4:
9071                 case CEE_LDELEM_R8:
9072                 case CEE_LDELEM_REF: {
9073                         MonoInst *addr;
9074
9075                         CHECK_STACK (2);
9076                         sp -= 2;
9077
9078                         if (*ip == CEE_LDELEM) {
9079                                 CHECK_OPSIZE (5);
9080                                 token = read32 (ip + 1);
9081                                 klass = mini_get_class (method, token, generic_context);
9082                                 CHECK_TYPELOAD (klass);
9083                                 mono_class_init (klass);
9084                         }
9085                         else
9086                                 klass = array_access_to_klass (*ip);
9087
9088                         if (sp [0]->type != STACK_OBJ)
9089                                 UNVERIFIED;
9090
9091                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
9092
9093                         if (sp [1]->opcode == OP_ICONST) {
9094                                 int array_reg = sp [0]->dreg;
9095                                 int index_reg = sp [1]->dreg;
9096                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
9097
9098                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
9099                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
9100                         } else {
9101                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
9102                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
9103                         }
9104                         *sp++ = ins;
9105                         if (*ip == CEE_LDELEM)
9106                                 ip += 5;
9107                         else
9108                                 ++ip;
9109                         break;
9110                 }
9111                 case CEE_STELEM_I:
9112                 case CEE_STELEM_I1:
9113                 case CEE_STELEM_I2:
9114                 case CEE_STELEM_I4:
9115                 case CEE_STELEM_I8:
9116                 case CEE_STELEM_R4:
9117                 case CEE_STELEM_R8:
9118                 case CEE_STELEM_REF:
9119                 case CEE_STELEM: {
9120                         MonoInst *addr;
9121
9122                         CHECK_STACK (3);
9123                         sp -= 3;
9124
9125                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
9126
9127                         if (*ip == CEE_STELEM) {
9128                                 CHECK_OPSIZE (5);
9129                                 token = read32 (ip + 1);
9130                                 klass = mini_get_class (method, token, generic_context);
9131                                 CHECK_TYPELOAD (klass);
9132                                 mono_class_init (klass);
9133                         }
9134                         else
9135                                 klass = array_access_to_klass (*ip);
9136
9137                         if (sp [0]->type != STACK_OBJ)
9138                                 UNVERIFIED;
9139
9140                         /* storing a NULL doesn't need any of the complex checks in stelemref */
9141                         if (generic_class_is_reference_type (cfg, klass) &&
9142                                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
9143                                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
9144                                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
9145                                 MonoInst *iargs [3];
9146
9147                                 if (!helper->slot)
9148                                         mono_class_setup_vtable (obj_array);
9149                                 g_assert (helper->slot);
9150
9151                                 if (sp [0]->type != STACK_OBJ)
9152                                         UNVERIFIED;
9153                                 if (sp [2]->type != STACK_OBJ)
9154                                         UNVERIFIED;
9155
9156                                 iargs [2] = sp [2];
9157                                 iargs [1] = sp [1];
9158                                 iargs [0] = sp [0];
9159
9160                                 mono_emit_method_call (cfg, helper, iargs, sp [0]);
9161                         } else {
9162                                 if (sp [1]->opcode == OP_ICONST) {
9163                                         int array_reg = sp [0]->dreg;
9164                                         int index_reg = sp [1]->dreg;
9165                                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
9166
9167                                         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
9168                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
9169                                 } else {
9170                                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
9171                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
9172                                 }
9173                         }
9174
9175                         if (*ip == CEE_STELEM)
9176                                 ip += 5;
9177                         else
9178                                 ++ip;
9179                         inline_costs += 1;
9180                         break;
9181                 }
9182                 case CEE_CKFINITE: {
9183                         CHECK_STACK (1);
9184                         --sp;
9185
9186                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
9187                         ins->sreg1 = sp [0]->dreg;
9188                         ins->dreg = alloc_freg (cfg);
9189                         ins->type = STACK_R8;
9190                         MONO_ADD_INS (bblock, ins);
9191
9192                         *sp++ = mono_decompose_opcode (cfg, ins);
9193
9194                         ++ip;
9195                         break;
9196                 }
9197                 case CEE_REFANYVAL: {
9198                         MonoInst *src_var, *src;
9199
9200                         int klass_reg = alloc_preg (cfg);
9201                         int dreg = alloc_preg (cfg);
9202
9203                         CHECK_STACK (1);
9204                         MONO_INST_NEW (cfg, ins, *ip);
9205                         --sp;
9206                         CHECK_OPSIZE (5);
9207                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
9208                         CHECK_TYPELOAD (klass);
9209                         mono_class_init (klass);
9210
9211                         if (cfg->generic_sharing_context)
9212                                 context_used = mono_class_check_context_used (klass);
9213
9214                         // FIXME:
9215                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9216                         if (!src_var)
9217                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
9218                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
9219                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
9220
9221                         if (context_used) {
9222                                 MonoInst *klass_ins;
9223
9224                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
9225                                                 klass, MONO_RGCTX_INFO_KLASS);
9226
9227                                 // FIXME:
9228                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
9229                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
9230                         } else {
9231                                 mini_emit_class_check (cfg, klass_reg, klass);
9232                         }
9233                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
9234                         ins->type = STACK_MP;
9235                         *sp++ = ins;
9236                         ip += 5;
9237                         break;
9238                 }
9239                 case CEE_MKREFANY: {
9240                         MonoInst *loc, *addr;
9241
9242                         CHECK_STACK (1);
9243                         MONO_INST_NEW (cfg, ins, *ip);
9244                         --sp;
9245                         CHECK_OPSIZE (5);
9246                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
9247                         CHECK_TYPELOAD (klass);
9248                         mono_class_init (klass);
9249
9250                         if (cfg->generic_sharing_context)
9251                                 context_used = mono_class_check_context_used (klass);
9252
9253                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
9254                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
9255
9256                         if (context_used) {
9257                                 MonoInst *const_ins;
9258                                 int type_reg = alloc_preg (cfg);
9259
9260                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
9261                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
9262                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
9263                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
9264                         } else if (cfg->compile_aot) {
9265                                 int const_reg = alloc_preg (cfg);
9266                                 int type_reg = alloc_preg (cfg);
9267
9268                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
9269                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
9270                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
9271                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
9272                         } else {
9273                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
9274                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
9275                         }
9276                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
9277
9278                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
9279                         ins->type = STACK_VTYPE;
9280                         ins->klass = mono_defaults.typed_reference_class;
9281                         *sp++ = ins;
9282                         ip += 5;
9283                         break;
9284                 }
9285                 case CEE_LDTOKEN: {
9286                         gpointer handle;
9287                         MonoClass *handle_class;
9288
9289                         CHECK_STACK_OVF (1);
9290
9291                         CHECK_OPSIZE (5);
9292                         n = read32 (ip + 1);
9293
9294                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
9295                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9296                                 handle = mono_method_get_wrapper_data (method, n);
9297                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
9298                                 if (handle_class == mono_defaults.typehandle_class)
9299                                         handle = &((MonoClass*)handle)->byval_arg;
9300                         }
9301                         else {
9302                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
9303                         }
9304                         if (!handle)
9305                                 LOAD_ERROR;
9306                         mono_class_init (handle_class);
9307                         if (cfg->generic_sharing_context) {
9308                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
9309                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
9310                                         /* This case handles ldtoken
9311                                            of an open type, like for
9312                                            typeof(Gen<>). */
9313                                         context_used = 0;
9314                                 } else if (handle_class == mono_defaults.typehandle_class) {
9315                                         /* If we get a MONO_TYPE_CLASS
9316                                            then we need to provide the
9317                                            open type, not an
9318                                            instantiation of it. */
9319                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
9320                                                 context_used = 0;
9321                                         else
9322                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
9323                                 } else if (handle_class == mono_defaults.fieldhandle_class)
9324                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
9325                                 else if (handle_class == mono_defaults.methodhandle_class)
9326                                         context_used = mono_method_check_context_used (handle);
9327                                 else
9328                                         g_assert_not_reached ();
9329                         }
9330
9331                         if ((cfg->opt & MONO_OPT_SHARED) &&
9332                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
9333                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
9334                                 MonoInst *addr, *vtvar, *iargs [3];
9335                                 int method_context_used;
9336
9337                                 if (cfg->generic_sharing_context)
9338                                         method_context_used = mono_method_check_context_used (method);
9339                                 else
9340                                         method_context_used = 0;
9341
9342                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
9343
9344                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9345                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
9346                                 if (method_context_used) {
9347                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
9348                                                 method, MONO_RGCTX_INFO_METHOD);
9349                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
9350                                 } else {
9351                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
9352                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
9353                                 }
9354                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9355
9356                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
9357
9358                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9359                         } else {
9360                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
9361                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
9362                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
9363                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
9364                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
9365                                         MonoClass *tclass = mono_class_from_mono_type (handle);
9366
9367                                         mono_class_init (tclass);
9368                                         if (context_used) {
9369                                                 ins = emit_get_rgctx_klass (cfg, context_used,
9370                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
9371                                         } else if (cfg->compile_aot) {
9372                                                 if (method->wrapper_type) {
9373                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
9374                                                                 /* Special case for static synchronized wrappers */
9375                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
9376                                                         } else {
9377                                                                 /* FIXME: n is not a normal token */
9378                                                                 cfg->disable_aot = TRUE;
9379                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
9380                                                         }
9381                                                 } else {
9382                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
9383                                                 }
9384                                         } else {
9385                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
9386                                         }
9387                                         ins->type = STACK_OBJ;
9388                                         ins->klass = cmethod->klass;
9389                                         ip += 5;
9390                                 } else {
9391                                         MonoInst *addr, *vtvar;
9392
9393                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
9394
9395                                         if (context_used) {
9396                                                 if (handle_class == mono_defaults.typehandle_class) {
9397                                                         ins = emit_get_rgctx_klass (cfg, context_used,
9398                                                                         mono_class_from_mono_type (handle),
9399                                                                         MONO_RGCTX_INFO_TYPE);
9400                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
9401                                                         ins = emit_get_rgctx_method (cfg, context_used,
9402                                                                         handle, MONO_RGCTX_INFO_METHOD);
9403                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
9404                                                         ins = emit_get_rgctx_field (cfg, context_used,
9405                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
9406                                                 } else {
9407                                                         g_assert_not_reached ();
9408                                                 }
9409                                         } else if (cfg->compile_aot) {
9410                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n);
9411                                         } else {
9412                                                 EMIT_NEW_PCONST (cfg, ins, handle);
9413                                         }
9414                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9415                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
9416                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9417                                 }
9418                         }
9419
9420                         *sp++ = ins;
9421                         ip += 5;
9422                         break;
9423                 }
9424                 case CEE_THROW:
9425                         CHECK_STACK (1);
9426                         MONO_INST_NEW (cfg, ins, OP_THROW);
9427                         --sp;
9428                         ins->sreg1 = sp [0]->dreg;
9429                         ip++;
9430                         bblock->out_of_line = TRUE;
9431                         MONO_ADD_INS (bblock, ins);
9432                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
9433                         MONO_ADD_INS (bblock, ins);
9434                         sp = stack_start;
9435                         
9436                         link_bblock (cfg, bblock, end_bblock);
9437                         start_new_bblock = 1;
9438                         break;
9439                 case CEE_ENDFINALLY:
9440                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
9441                         MONO_ADD_INS (bblock, ins);
9442                         ip++;
9443                         start_new_bblock = 1;
9444
9445                         /*
9446                          * Control will leave the method so empty the stack, otherwise
9447                          * the next basic block will start with a nonempty stack.
9448                          */
9449                         while (sp != stack_start) {
9450                                 sp--;
9451                         }
9452                         break;
9453                 case CEE_LEAVE:
9454                 case CEE_LEAVE_S: {
9455                         GList *handlers;
9456
9457                         if (*ip == CEE_LEAVE) {
9458                                 CHECK_OPSIZE (5);
9459                                 target = ip + 5 + (gint32)read32(ip + 1);
9460                         } else {
9461                                 CHECK_OPSIZE (2);
9462                                 target = ip + 2 + (signed char)(ip [1]);
9463                         }
9464
9465                         /* empty the stack */
9466                         while (sp != stack_start) {
9467                                 sp--;
9468                         }
9469
9470                         /* 
9471                          * If this leave statement is in a catch block, check for a
9472                          * pending exception, and rethrow it if necessary.
9473                          * We avoid doing this in runtime invoke wrappers, since those are called
9474                          * by native code which excepts the wrapper to catch all exceptions.
9475                          */
9476                         for (i = 0; i < header->num_clauses; ++i) {
9477                                 MonoExceptionClause *clause = &header->clauses [i];
9478
9479                                 /* 
9480                                  * Use <= in the final comparison to handle clauses with multiple
9481                                  * leave statements, like in bug #78024.
9482                                  * The ordering of the exception clauses guarantees that we find the
9483                                  * innermost clause.
9484                                  */
9485                                 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) {
9486                                         MonoInst *exc_ins;
9487                                         MonoBasicBlock *dont_throw;
9488
9489                                         /*
9490                                           MonoInst *load;
9491
9492                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
9493                                         */
9494
9495                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
9496
9497                                         NEW_BBLOCK (cfg, dont_throw);
9498
9499                                         /*
9500                                          * Currently, we always rethrow the abort exception, despite the 
9501                                          * fact that this is not correct. See thread6.cs for an example. 
9502                                          * But propagating the abort exception is more important than 
9503                                          * getting the sematics right.
9504                                          */
9505                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
9506                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
9507                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
9508
9509                                         MONO_START_BB (cfg, dont_throw);
9510                                         bblock = cfg->cbb;
9511                                 }
9512                         }
9513
9514                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9515                                 GList *tmp;
9516                                 MonoExceptionClause *clause;
9517
9518                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9519                                         clause = tmp->data;
9520                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
9521                                         g_assert (tblock);
9522                                         link_bblock (cfg, bblock, tblock);
9523                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9524                                         ins->inst_target_bb = tblock;
9525                                         ins->inst_eh_block = clause;
9526                                         MONO_ADD_INS (bblock, ins);
9527                                         bblock->has_call_handler = 1;
9528                                         if (COMPILE_LLVM (cfg)) {
9529                                                 MonoBasicBlock *target_bb;
9530
9531                                                 /* 
9532                                                  * Link the finally bblock with the target, since it will
9533                                                  * conceptually branch there.
9534                                                  * FIXME: Have to link the bblock containing the endfinally.
9535                                                  */
9536                                                 GET_BBLOCK (cfg, target_bb, target);
9537                                                 link_bblock (cfg, tblock, target_bb);
9538                                         }
9539                                 }
9540                                 g_list_free (handlers);
9541                         } 
9542
9543                         MONO_INST_NEW (cfg, ins, OP_BR);
9544                         MONO_ADD_INS (bblock, ins);
9545                         GET_BBLOCK (cfg, tblock, target);
9546                         link_bblock (cfg, bblock, tblock);
9547                         ins->inst_target_bb = tblock;
9548                         start_new_bblock = 1;
9549
9550                         if (*ip == CEE_LEAVE)
9551                                 ip += 5;
9552                         else
9553                                 ip += 2;
9554
9555                         break;
9556                 }
9557
9558                         /*
9559                          * Mono specific opcodes
9560                          */
9561                 case MONO_CUSTOM_PREFIX: {
9562
9563                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9564
9565                         CHECK_OPSIZE (2);
9566                         switch (ip [1]) {
9567                         case CEE_MONO_ICALL: {
9568                                 gpointer func;
9569                                 MonoJitICallInfo *info;
9570
9571                                 token = read32 (ip + 2);
9572                                 func = mono_method_get_wrapper_data (method, token);
9573                                 info = mono_find_jit_icall_by_addr (func);
9574                                 g_assert (info);
9575
9576                                 CHECK_STACK (info->sig->param_count);
9577                                 sp -= info->sig->param_count;
9578
9579                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
9580                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
9581                                         *sp++ = ins;
9582
9583                                 ip += 6;
9584                                 inline_costs += 10 * num_calls++;
9585
9586                                 break;
9587                         }
9588                         case CEE_MONO_LDPTR: {
9589                                 gpointer ptr;
9590
9591                                 CHECK_STACK_OVF (1);
9592                                 CHECK_OPSIZE (6);
9593                                 token = read32 (ip + 2);
9594
9595                                 ptr = mono_method_get_wrapper_data (method, token);
9596                                 if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9597                                         MonoJitICallInfo *callinfo;
9598                                         const char *icall_name;
9599
9600                                         icall_name = method->name + strlen ("__icall_wrapper_");
9601                                         g_assert (icall_name);
9602                                         callinfo = mono_find_jit_icall_by_name (icall_name);
9603                                         g_assert (callinfo);
9604                                                 
9605                                         if (ptr == callinfo->func) {
9606                                                 /* Will be transformed into an AOTCONST later */
9607                                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9608                                                 *sp++ = ins;
9609                                                 ip += 6;
9610                                                 break;
9611                                         }
9612                                 }
9613                                 /* FIXME: Generalize this */
9614                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9615                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9616                                         *sp++ = ins;
9617                                         ip += 6;
9618                                         break;
9619                                 }
9620                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9621                                 *sp++ = ins;
9622                                 ip += 6;
9623                                 inline_costs += 10 * num_calls++;
9624                                 /* Can't embed random pointers into AOT code */
9625                                 cfg->disable_aot = 1;
9626                                 break;
9627                         }
9628                         case CEE_MONO_ICALL_ADDR: {
9629                                 MonoMethod *cmethod;
9630                                 gpointer ptr;
9631
9632                                 CHECK_STACK_OVF (1);
9633                                 CHECK_OPSIZE (6);
9634                                 token = read32 (ip + 2);
9635
9636                                 cmethod = mono_method_get_wrapper_data (method, token);
9637
9638                                 if (cfg->compile_aot) {
9639                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9640                                 } else {
9641                                         ptr = mono_lookup_internal_call (cmethod);
9642                                         g_assert (ptr);
9643                                         EMIT_NEW_PCONST (cfg, ins, ptr);
9644                                 }
9645                                 *sp++ = ins;
9646                                 ip += 6;
9647                                 break;
9648                         }
9649                         case CEE_MONO_VTADDR: {
9650                                 MonoInst *src_var, *src;
9651
9652                                 CHECK_STACK (1);
9653                                 --sp;
9654
9655                                 // FIXME:
9656                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9657                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
9658                                 *sp++ = src;
9659                                 ip += 2;
9660                                 break;
9661                         }
9662                         case CEE_MONO_NEWOBJ: {
9663                                 MonoInst *iargs [2];
9664
9665                                 CHECK_STACK_OVF (1);
9666                                 CHECK_OPSIZE (6);
9667                                 token = read32 (ip + 2);
9668                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9669                                 mono_class_init (klass);
9670                                 NEW_DOMAINCONST (cfg, iargs [0]);
9671                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
9672                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9673                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
9674                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
9675                                 ip += 6;
9676                                 inline_costs += 10 * num_calls++;
9677                                 break;
9678                         }
9679                         case CEE_MONO_OBJADDR:
9680                                 CHECK_STACK (1);
9681                                 --sp;
9682                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
9683                                 ins->dreg = alloc_preg (cfg);
9684                                 ins->sreg1 = sp [0]->dreg;
9685                                 ins->type = STACK_MP;
9686                                 MONO_ADD_INS (cfg->cbb, ins);
9687                                 *sp++ = ins;
9688                                 ip += 2;
9689                                 break;
9690                         case CEE_MONO_LDNATIVEOBJ:
9691                                 /*
9692                                  * Similar to LDOBJ, but instead load the unmanaged 
9693                                  * representation of the vtype to the stack.
9694                                  */
9695                                 CHECK_STACK (1);
9696                                 CHECK_OPSIZE (6);
9697                                 --sp;
9698                                 token = read32 (ip + 2);
9699                                 klass = mono_method_get_wrapper_data (method, token);
9700                                 g_assert (klass->valuetype);
9701                                 mono_class_init (klass);
9702
9703                                 {
9704                                         MonoInst *src, *dest, *temp;
9705
9706                                         src = sp [0];
9707                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
9708                                         temp->backend.is_pinvoke = 1;
9709                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
9710                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
9711
9712                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
9713                                         dest->type = STACK_VTYPE;
9714                                         dest->klass = klass;
9715
9716                                         *sp ++ = dest;
9717                                         ip += 6;
9718                                 }
9719                                 break;
9720                         case CEE_MONO_RETOBJ: {
9721                                 /*
9722                                  * Same as RET, but return the native representation of a vtype
9723                                  * to the caller.
9724                                  */
9725                                 g_assert (cfg->ret);
9726                                 g_assert (mono_method_signature (method)->pinvoke); 
9727                                 CHECK_STACK (1);
9728                                 --sp;
9729                                 
9730                                 CHECK_OPSIZE (6);
9731                                 token = read32 (ip + 2);    
9732                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9733
9734                                 if (!cfg->vret_addr) {
9735                                         g_assert (cfg->ret_var_is_local);
9736
9737                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
9738                                 } else {
9739                                         EMIT_NEW_RETLOADA (cfg, ins);
9740                                 }
9741                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
9742                                 
9743                                 if (sp != stack_start)
9744                                         UNVERIFIED;
9745                                 
9746                                 MONO_INST_NEW (cfg, ins, OP_BR);
9747                                 ins->inst_target_bb = end_bblock;
9748                                 MONO_ADD_INS (bblock, ins);
9749                                 link_bblock (cfg, bblock, end_bblock);
9750                                 start_new_bblock = 1;
9751                                 ip += 6;
9752                                 break;
9753                         }
9754                         case CEE_MONO_CISINST:
9755                         case CEE_MONO_CCASTCLASS: {
9756                                 int token;
9757                                 CHECK_STACK (1);
9758                                 --sp;
9759                                 CHECK_OPSIZE (6);
9760                                 token = read32 (ip + 2);
9761                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9762                                 if (ip [1] == CEE_MONO_CISINST)
9763                                         ins = handle_cisinst (cfg, klass, sp [0]);
9764                                 else
9765                                         ins = handle_ccastclass (cfg, klass, sp [0]);
9766                                 bblock = cfg->cbb;
9767                                 *sp++ = ins;
9768                                 ip += 6;
9769                                 break;
9770                         }
9771                         case CEE_MONO_SAVE_LMF:
9772                         case CEE_MONO_RESTORE_LMF:
9773 #ifdef MONO_ARCH_HAVE_LMF_OPS
9774                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9775                                 MONO_ADD_INS (bblock, ins);
9776                                 cfg->need_lmf_area = TRUE;
9777 #endif
9778                                 ip += 2;
9779                                 break;
9780                         case CEE_MONO_CLASSCONST:
9781                                 CHECK_STACK_OVF (1);
9782                                 CHECK_OPSIZE (6);
9783                                 token = read32 (ip + 2);
9784                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9785                                 *sp++ = ins;
9786                                 ip += 6;
9787                                 inline_costs += 10 * num_calls++;
9788                                 break;
9789                         case CEE_MONO_NOT_TAKEN:
9790                                 bblock->out_of_line = TRUE;
9791                                 ip += 2;
9792                                 break;
9793                         case CEE_MONO_TLS:
9794                                 CHECK_STACK_OVF (1);
9795                                 CHECK_OPSIZE (6);
9796                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9797                                 ins->dreg = alloc_preg (cfg);
9798                                 ins->inst_offset = (gint32)read32 (ip + 2);
9799                                 ins->type = STACK_PTR;
9800                                 MONO_ADD_INS (bblock, ins);
9801                                 *sp++ = ins;
9802                                 ip += 6;
9803                                 break;
9804                         case CEE_MONO_DYN_CALL: {
9805                                 MonoCallInst *call;
9806
9807                                 /* It would be easier to call a trampoline, but that would put an
9808                                  * extra frame on the stack, confusing exception handling. So
9809                                  * implement it inline using an opcode for now.
9810                                  */
9811
9812                                 if (!cfg->dyn_call_var) {
9813                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9814                                         /* prevent it from being register allocated */
9815                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
9816                                 }
9817
9818                                 /* Has to use a call inst since it local regalloc expects it */
9819                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
9820                                 ins = (MonoInst*)call;
9821                                 sp -= 2;
9822                                 ins->sreg1 = sp [0]->dreg;
9823                                 ins->sreg2 = sp [1]->dreg;
9824                                 MONO_ADD_INS (bblock, ins);
9825
9826 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
9827                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
9828 #endif
9829
9830                                 ip += 2;
9831                                 inline_costs += 10 * num_calls++;
9832
9833                                 break;
9834                         }
9835                         default:
9836                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9837                                 break;
9838                         }
9839                         break;
9840                 }
9841
9842                 case CEE_PREFIX1: {
9843                         CHECK_OPSIZE (2);
9844                         switch (ip [1]) {
9845                         case CEE_ARGLIST: {
9846                                 /* somewhat similar to LDTOKEN */
9847                                 MonoInst *addr, *vtvar;
9848                                 CHECK_STACK_OVF (1);
9849                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9850
9851                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9852                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
9853
9854                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9855                                 ins->type = STACK_VTYPE;
9856                                 ins->klass = mono_defaults.argumenthandle_class;
9857                                 *sp++ = ins;
9858                                 ip += 2;
9859                                 break;
9860                         }
9861                         case CEE_CEQ:
9862                         case CEE_CGT:
9863                         case CEE_CGT_UN:
9864                         case CEE_CLT:
9865                         case CEE_CLT_UN: {
9866                                 MonoInst *cmp;
9867                                 CHECK_STACK (2);
9868                                 /*
9869                                  * The following transforms:
9870                                  *    CEE_CEQ    into OP_CEQ
9871                                  *    CEE_CGT    into OP_CGT
9872                                  *    CEE_CGT_UN into OP_CGT_UN
9873                                  *    CEE_CLT    into OP_CLT
9874                                  *    CEE_CLT_UN into OP_CLT_UN
9875                                  */
9876                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9877                                 
9878                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9879                                 sp -= 2;
9880                                 cmp->sreg1 = sp [0]->dreg;
9881                                 cmp->sreg2 = sp [1]->dreg;
9882                                 type_from_op (cmp, sp [0], sp [1]);
9883                                 CHECK_TYPE (cmp);
9884                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9885                                         cmp->opcode = OP_LCOMPARE;
9886                                 else if (sp [0]->type == STACK_R8)
9887                                         cmp->opcode = OP_FCOMPARE;
9888                                 else
9889                                         cmp->opcode = OP_ICOMPARE;
9890                                 MONO_ADD_INS (bblock, cmp);
9891                                 ins->type = STACK_I4;
9892                                 ins->dreg = alloc_dreg (cfg, ins->type);
9893                                 type_from_op (ins, sp [0], sp [1]);
9894
9895                                 if (cmp->opcode == OP_FCOMPARE) {
9896                                         /*
9897                                          * The backends expect the fceq opcodes to do the
9898                                          * comparison too.
9899                                          */
9900                                         cmp->opcode = OP_NOP;
9901                                         ins->sreg1 = cmp->sreg1;
9902                                         ins->sreg2 = cmp->sreg2;
9903                                 }
9904                                 MONO_ADD_INS (bblock, ins);
9905                                 *sp++ = ins;
9906                                 ip += 2;
9907                                 break;
9908                         }
9909                         case CEE_LDFTN: {
9910                                 MonoInst *argconst;
9911                                 MonoMethod *cil_method;
9912                                 gboolean needs_static_rgctx_invoke;
9913
9914                                 CHECK_STACK_OVF (1);
9915                                 CHECK_OPSIZE (6);
9916                                 n = read32 (ip + 2);
9917                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9918                                 if (!cmethod || mono_loader_get_last_error ())
9919                                         LOAD_ERROR;
9920                                 mono_class_init (cmethod->klass);
9921
9922                                 mono_save_token_info (cfg, image, n, cmethod);
9923
9924                                 if (cfg->generic_sharing_context)
9925                                         context_used = mono_method_check_context_used (cmethod);
9926
9927                                 needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
9928  
9929                                 cil_method = cmethod;
9930                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9931                                         METHOD_ACCESS_FAILURE;
9932
9933                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9934                                         if (check_linkdemand (cfg, method, cmethod))
9935                                                 INLINE_FAILURE;
9936                                         CHECK_CFG_EXCEPTION;
9937                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9938                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9939                                 }
9940
9941                                 /* 
9942                                  * Optimize the common case of ldftn+delegate creation
9943                                  */
9944                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
9945                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
9946                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9947                                                 MonoInst *target_ins;
9948                                                 MonoMethod *invoke;
9949                                                 int invoke_context_used = 0;
9950
9951                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
9952                                                 if (!invoke || !mono_method_signature (invoke))
9953                                                         LOAD_ERROR;
9954
9955                                                 if (cfg->generic_sharing_context)
9956                                                         invoke_context_used = mono_method_check_context_used (invoke);
9957
9958                                                 target_ins = sp [-1];
9959
9960                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
9961                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
9962                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
9963                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
9964                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
9965                                                         }
9966                                                 }
9967
9968 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
9969                                                 /* FIXME: SGEN support */
9970                                                 if (invoke_context_used == 0) {
9971                                                         ip += 6;
9972                                                         if (cfg->verbose_level > 3)
9973                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9974                                                         sp --;
9975                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
9976                                                         CHECK_CFG_EXCEPTION;
9977                                                         ip += 5;                        
9978                                                         sp ++;
9979                                                         break;
9980                                                 }
9981 #endif
9982                                         }
9983                                 }
9984
9985                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
9986                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
9987                                 *sp++ = ins;
9988                                 
9989                                 ip += 6;
9990                                 inline_costs += 10 * num_calls++;
9991                                 break;
9992                         }
9993                         case CEE_LDVIRTFTN: {
9994                                 MonoInst *args [2];
9995
9996                                 CHECK_STACK (1);
9997                                 CHECK_OPSIZE (6);
9998                                 n = read32 (ip + 2);
9999                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
10000                                 if (!cmethod || mono_loader_get_last_error ())
10001                                         LOAD_ERROR;
10002                                 mono_class_init (cmethod->klass);
10003  
10004                                 if (cfg->generic_sharing_context)
10005                                         context_used = mono_method_check_context_used (cmethod);
10006
10007                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
10008                                         if (check_linkdemand (cfg, method, cmethod))
10009                                                 INLINE_FAILURE;
10010                                         CHECK_CFG_EXCEPTION;
10011                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
10012                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10013                                 }
10014
10015                                 --sp;
10016                                 args [0] = *sp;
10017
10018                                 args [1] = emit_get_rgctx_method (cfg, context_used,
10019                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
10020
10021                                 if (context_used)
10022                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
10023                                 else
10024                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
10025
10026                                 ip += 6;
10027                                 inline_costs += 10 * num_calls++;
10028                                 break;
10029                         }
10030                         case CEE_LDARG:
10031                                 CHECK_STACK_OVF (1);
10032                                 CHECK_OPSIZE (4);
10033                                 n = read16 (ip + 2);
10034                                 CHECK_ARG (n);
10035                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
10036                                 *sp++ = ins;
10037                                 ip += 4;
10038                                 break;
10039                         case CEE_LDARGA:
10040                                 CHECK_STACK_OVF (1);
10041                                 CHECK_OPSIZE (4);
10042                                 n = read16 (ip + 2);
10043                                 CHECK_ARG (n);
10044                                 NEW_ARGLOADA (cfg, ins, n);
10045                                 MONO_ADD_INS (cfg->cbb, ins);
10046                                 *sp++ = ins;
10047                                 ip += 4;
10048                                 break;
10049                         case CEE_STARG:
10050                                 CHECK_STACK (1);
10051                                 --sp;
10052                                 CHECK_OPSIZE (4);
10053                                 n = read16 (ip + 2);
10054                                 CHECK_ARG (n);
10055                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
10056                                         UNVERIFIED;
10057                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
10058                                 ip += 4;
10059                                 break;
10060                         case CEE_LDLOC:
10061                                 CHECK_STACK_OVF (1);
10062                                 CHECK_OPSIZE (4);
10063                                 n = read16 (ip + 2);
10064                                 CHECK_LOCAL (n);
10065                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
10066                                 *sp++ = ins;
10067                                 ip += 4;
10068                                 break;
10069                         case CEE_LDLOCA: {
10070                                 unsigned char *tmp_ip;
10071                                 CHECK_STACK_OVF (1);
10072                                 CHECK_OPSIZE (4);
10073                                 n = read16 (ip + 2);
10074                                 CHECK_LOCAL (n);
10075
10076                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
10077                                         ip = tmp_ip;
10078                                         inline_costs += 1;
10079                                         break;
10080                                 }                       
10081                                 
10082                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
10083                                 *sp++ = ins;
10084                                 ip += 4;
10085                                 break;
10086                         }
10087                         case CEE_STLOC:
10088                                 CHECK_STACK (1);
10089                                 --sp;
10090                                 CHECK_OPSIZE (4);
10091                                 n = read16 (ip + 2);
10092                                 CHECK_LOCAL (n);
10093                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
10094                                         UNVERIFIED;
10095                                 emit_stloc_ir (cfg, sp, header, n);
10096                                 ip += 4;
10097                                 inline_costs += 1;
10098                                 break;
10099                         case CEE_LOCALLOC:
10100                                 CHECK_STACK (1);
10101                                 --sp;
10102                                 if (sp != stack_start) 
10103                                         UNVERIFIED;
10104                                 if (cfg->method != method) 
10105                                         /* 
10106                                          * Inlining this into a loop in a parent could lead to 
10107                                          * stack overflows which is different behavior than the
10108                                          * non-inlined case, thus disable inlining in this case.
10109                                          */
10110                                         goto inline_failure;
10111
10112                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
10113                                 ins->dreg = alloc_preg (cfg);
10114                                 ins->sreg1 = sp [0]->dreg;
10115                                 ins->type = STACK_PTR;
10116                                 MONO_ADD_INS (cfg->cbb, ins);
10117
10118                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
10119                                 if (init_locals)
10120                                         ins->flags |= MONO_INST_INIT;
10121
10122                                 *sp++ = ins;
10123                                 ip += 2;
10124                                 break;
10125                         case CEE_ENDFILTER: {
10126                                 MonoExceptionClause *clause, *nearest;
10127                                 int cc, nearest_num;
10128
10129                                 CHECK_STACK (1);
10130                                 --sp;
10131                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
10132                                         UNVERIFIED;
10133                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
10134                                 ins->sreg1 = (*sp)->dreg;
10135                                 MONO_ADD_INS (bblock, ins);
10136                                 start_new_bblock = 1;
10137                                 ip += 2;
10138
10139                                 nearest = NULL;
10140                                 nearest_num = 0;
10141                                 for (cc = 0; cc < header->num_clauses; ++cc) {
10142                                         clause = &header->clauses [cc];
10143                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
10144                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
10145                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
10146                                                 nearest = clause;
10147                                                 nearest_num = cc;
10148                                         }
10149                                 }
10150                                 g_assert (nearest);
10151                                 if ((ip - header->code) != nearest->handler_offset)
10152                                         UNVERIFIED;
10153
10154                                 break;
10155                         }
10156                         case CEE_UNALIGNED_:
10157                                 ins_flag |= MONO_INST_UNALIGNED;
10158                                 /* FIXME: record alignment? we can assume 1 for now */
10159                                 CHECK_OPSIZE (3);
10160                                 ip += 3;
10161                                 break;
10162                         case CEE_VOLATILE_:
10163                                 ins_flag |= MONO_INST_VOLATILE;
10164                                 ip += 2;
10165                                 break;
10166                         case CEE_TAIL_:
10167                                 ins_flag   |= MONO_INST_TAILCALL;
10168                                 cfg->flags |= MONO_CFG_HAS_TAIL;
10169                                 /* Can't inline tail calls at this time */
10170                                 inline_costs += 100000;
10171                                 ip += 2;
10172                                 break;
10173                         case CEE_INITOBJ:
10174                                 CHECK_STACK (1);
10175                                 --sp;
10176                                 CHECK_OPSIZE (6);
10177                                 token = read32 (ip + 2);
10178                                 klass = mini_get_class (method, token, generic_context);
10179                                 CHECK_TYPELOAD (klass);
10180                                 if (generic_class_is_reference_type (cfg, klass))
10181                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
10182                                 else
10183                                         mini_emit_initobj (cfg, *sp, NULL, klass);
10184                                 ip += 6;
10185                                 inline_costs += 1;
10186                                 break;
10187                         case CEE_CONSTRAINED_:
10188                                 CHECK_OPSIZE (6);
10189                                 token = read32 (ip + 2);
10190                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
10191                                         constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
10192                                 else
10193                                         constrained_call = mono_class_get_full (image, token, generic_context);
10194                                 CHECK_TYPELOAD (constrained_call);
10195                                 ip += 6;
10196                                 break;
10197                         case CEE_CPBLK:
10198                         case CEE_INITBLK: {
10199                                 MonoInst *iargs [3];
10200                                 CHECK_STACK (3);
10201                                 sp -= 3;
10202
10203                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
10204                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
10205                                 } 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)) {
10206                                         /* emit_memset only works when val == 0 */
10207                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
10208                                 } else {
10209                                         iargs [0] = sp [0];
10210                                         iargs [1] = sp [1];
10211                                         iargs [2] = sp [2];
10212                                         if (ip [1] == CEE_CPBLK) {
10213                                                 MonoMethod *memcpy_method = get_memcpy_method ();
10214                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10215                                         } else {
10216                                                 MonoMethod *memset_method = get_memset_method ();
10217                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
10218                                         }
10219                                 }
10220                                 ip += 2;
10221                                 inline_costs += 1;
10222                                 break;
10223                         }
10224                         case CEE_NO_:
10225                                 CHECK_OPSIZE (3);
10226                                 if (ip [2] & 0x1)
10227                                         ins_flag |= MONO_INST_NOTYPECHECK;
10228                                 if (ip [2] & 0x2)
10229                                         ins_flag |= MONO_INST_NORANGECHECK;
10230                                 /* we ignore the no-nullcheck for now since we
10231                                  * really do it explicitly only when doing callvirt->call
10232                                  */
10233                                 ip += 3;
10234                                 break;
10235                         case CEE_RETHROW: {
10236                                 MonoInst *load;
10237                                 int handler_offset = -1;
10238
10239                                 for (i = 0; i < header->num_clauses; ++i) {
10240                                         MonoExceptionClause *clause = &header->clauses [i];
10241                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
10242                                                 handler_offset = clause->handler_offset;
10243                                                 break;
10244                                         }
10245                                 }
10246
10247                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
10248
10249                                 g_assert (handler_offset != -1);
10250
10251                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
10252                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
10253                                 ins->sreg1 = load->dreg;
10254                                 MONO_ADD_INS (bblock, ins);
10255
10256                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10257                                 MONO_ADD_INS (bblock, ins);
10258
10259                                 sp = stack_start;
10260                                 link_bblock (cfg, bblock, end_bblock);
10261                                 start_new_bblock = 1;
10262                                 ip += 2;
10263                                 break;
10264                         }
10265                         case CEE_SIZEOF: {
10266                                 guint32 align;
10267                                 int ialign;
10268
10269                                 CHECK_STACK_OVF (1);
10270                                 CHECK_OPSIZE (6);
10271                                 token = read32 (ip + 2);
10272                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic) {
10273                                         MonoType *type = mono_type_create_from_typespec (image, token);
10274                                         token = mono_type_size (type, &ialign);
10275                                 } else {
10276                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
10277                                         CHECK_TYPELOAD (klass);
10278                                         mono_class_init (klass);
10279                                         token = mono_class_value_size (klass, &align);
10280                                 }
10281                                 EMIT_NEW_ICONST (cfg, ins, token);
10282                                 *sp++= ins;
10283                                 ip += 6;
10284                                 break;
10285                         }
10286                         case CEE_REFANYTYPE: {
10287                                 MonoInst *src_var, *src;
10288
10289                                 CHECK_STACK (1);
10290                                 --sp;
10291
10292                                 // FIXME:
10293                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10294                                 if (!src_var)
10295                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10296                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10297                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
10298                                 *sp++ = ins;
10299                                 ip += 2;
10300                                 break;
10301                         }
10302                         case CEE_READONLY_:
10303                                 readonly = TRUE;
10304                                 ip += 2;
10305                                 break;
10306
10307                         case CEE_UNUSED56:
10308                         case CEE_UNUSED57:
10309                         case CEE_UNUSED70:
10310                         case CEE_UNUSED:
10311                         case CEE_UNUSED99:
10312                                 UNVERIFIED;
10313                                 
10314                         default:
10315                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
10316                                 UNVERIFIED;
10317                         }
10318                         break;
10319                 }
10320                 case CEE_UNUSED58:
10321                 case CEE_UNUSED1:
10322                         UNVERIFIED;
10323
10324                 default:
10325                         g_warning ("opcode 0x%02x not handled", *ip);
10326                         UNVERIFIED;
10327                 }
10328         }
10329         if (start_new_bblock != 1)
10330                 UNVERIFIED;
10331
10332         bblock->cil_length = ip - bblock->cil_code;
10333         bblock->next_bb = end_bblock;
10334
10335         if (cfg->method == method && cfg->domainvar) {
10336                 MonoInst *store;
10337                 MonoInst *get_domain;
10338
10339                 cfg->cbb = init_localsbb;
10340
10341                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
10342                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
10343                 }
10344                 else {
10345                         get_domain->dreg = alloc_preg (cfg);
10346                         MONO_ADD_INS (cfg->cbb, get_domain);
10347                 }               
10348                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
10349                 MONO_ADD_INS (cfg->cbb, store);
10350         }
10351
10352 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
10353         if (cfg->compile_aot)
10354                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
10355                 mono_get_got_var (cfg);
10356 #endif
10357
10358         if (cfg->method == method && cfg->got_var)
10359                 mono_emit_load_got_addr (cfg);
10360
10361         if (init_locals) {
10362                 MonoInst *store;
10363
10364                 cfg->cbb = init_localsbb;
10365                 cfg->ip = NULL;
10366                 for (i = 0; i < header->num_locals; ++i) {
10367                         MonoType *ptype = header->locals [i];
10368                         int t = ptype->type;
10369                         dreg = cfg->locals [i]->dreg;
10370
10371                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
10372                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
10373                         if (ptype->byref) {
10374                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
10375                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
10376                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
10377                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
10378                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
10379                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
10380                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
10381                                 ins->type = STACK_R8;
10382                                 ins->inst_p0 = (void*)&r8_0;
10383                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
10384                                 MONO_ADD_INS (init_localsbb, ins);
10385                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
10386                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
10387                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
10388                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
10389                         } else {
10390                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
10391                         }
10392                 }
10393         }
10394
10395         if (cfg->init_ref_vars && cfg->method == method) {
10396                 /* Emit initialization for ref vars */
10397                 // FIXME: Avoid duplication initialization for IL locals.
10398                 for (i = 0; i < cfg->num_varinfo; ++i) {
10399                         MonoInst *ins = cfg->varinfo [i];
10400
10401                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
10402                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
10403                 }
10404         }
10405
10406         /* Add a sequence point for method entry/exit events */
10407         if (seq_points) {
10408                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
10409                 MONO_ADD_INS (init_localsbb, ins);
10410                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
10411                 MONO_ADD_INS (cfg->bb_exit, ins);
10412         }
10413
10414         cfg->ip = NULL;
10415
10416         if (cfg->method == method) {
10417                 MonoBasicBlock *bb;
10418                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10419                         bb->region = mono_find_block_region (cfg, bb->real_offset);
10420                         if (cfg->spvars)
10421                                 mono_create_spvar_for_region (cfg, bb->region);
10422                         if (cfg->verbose_level > 2)
10423                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
10424                 }
10425         }
10426
10427         g_slist_free (class_inits);
10428         dont_inline = g_list_remove (dont_inline, method);
10429
10430         if (inline_costs < 0) {
10431                 char *mname;
10432
10433                 /* Method is too large */
10434                 mname = mono_method_full_name (method, TRUE);
10435                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
10436                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
10437                 g_free (mname);
10438                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10439                 mono_basic_block_free (original_bb);
10440                 return -1;
10441         }
10442
10443         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
10444                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
10445
10446         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10447         mono_basic_block_free (original_bb);
10448         return inline_costs;
10449  
10450  exception_exit:
10451         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
10452         goto cleanup;
10453
10454  inline_failure:
10455         goto cleanup;
10456
10457  load_error:
10458         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
10459         goto cleanup;
10460
10461  unverified:
10462         set_exception_type_from_invalid_il (cfg, method, ip);
10463         goto cleanup;
10464
10465  cleanup:
10466         g_slist_free (class_inits);
10467         mono_basic_block_free (original_bb);
10468         dont_inline = g_list_remove (dont_inline, method);
10469         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10470         return -1;
10471 }
10472
10473 static int
10474 store_membase_reg_to_store_membase_imm (int opcode)
10475 {
10476         switch (opcode) {
10477         case OP_STORE_MEMBASE_REG:
10478                 return OP_STORE_MEMBASE_IMM;
10479         case OP_STOREI1_MEMBASE_REG:
10480                 return OP_STOREI1_MEMBASE_IMM;
10481         case OP_STOREI2_MEMBASE_REG:
10482                 return OP_STOREI2_MEMBASE_IMM;
10483         case OP_STOREI4_MEMBASE_REG:
10484                 return OP_STOREI4_MEMBASE_IMM;
10485         case OP_STOREI8_MEMBASE_REG:
10486                 return OP_STOREI8_MEMBASE_IMM;
10487         default:
10488                 g_assert_not_reached ();
10489         }
10490
10491         return -1;
10492 }               
10493
10494 #endif /* DISABLE_JIT */
10495
10496 int
10497 mono_op_to_op_imm (int opcode)
10498 {
10499         switch (opcode) {
10500         case OP_IADD:
10501                 return OP_IADD_IMM;
10502         case OP_ISUB:
10503                 return OP_ISUB_IMM;
10504         case OP_IDIV:
10505                 return OP_IDIV_IMM;
10506         case OP_IDIV_UN:
10507                 return OP_IDIV_UN_IMM;
10508         case OP_IREM:
10509                 return OP_IREM_IMM;
10510         case OP_IREM_UN:
10511                 return OP_IREM_UN_IMM;
10512         case OP_IMUL:
10513                 return OP_IMUL_IMM;
10514         case OP_IAND:
10515                 return OP_IAND_IMM;
10516         case OP_IOR:
10517                 return OP_IOR_IMM;
10518         case OP_IXOR:
10519                 return OP_IXOR_IMM;
10520         case OP_ISHL:
10521                 return OP_ISHL_IMM;
10522         case OP_ISHR:
10523                 return OP_ISHR_IMM;
10524         case OP_ISHR_UN:
10525                 return OP_ISHR_UN_IMM;
10526
10527         case OP_LADD:
10528                 return OP_LADD_IMM;
10529         case OP_LSUB:
10530                 return OP_LSUB_IMM;
10531         case OP_LAND:
10532                 return OP_LAND_IMM;
10533         case OP_LOR:
10534                 return OP_LOR_IMM;
10535         case OP_LXOR:
10536                 return OP_LXOR_IMM;
10537         case OP_LSHL:
10538                 return OP_LSHL_IMM;
10539         case OP_LSHR:
10540                 return OP_LSHR_IMM;
10541         case OP_LSHR_UN:
10542                 return OP_LSHR_UN_IMM;          
10543
10544         case OP_COMPARE:
10545                 return OP_COMPARE_IMM;
10546         case OP_ICOMPARE:
10547                 return OP_ICOMPARE_IMM;
10548         case OP_LCOMPARE:
10549                 return OP_LCOMPARE_IMM;
10550
10551         case OP_STORE_MEMBASE_REG:
10552                 return OP_STORE_MEMBASE_IMM;
10553         case OP_STOREI1_MEMBASE_REG:
10554                 return OP_STOREI1_MEMBASE_IMM;
10555         case OP_STOREI2_MEMBASE_REG:
10556                 return OP_STOREI2_MEMBASE_IMM;
10557         case OP_STOREI4_MEMBASE_REG:
10558                 return OP_STOREI4_MEMBASE_IMM;
10559
10560 #if defined(TARGET_X86) || defined (TARGET_AMD64)
10561         case OP_X86_PUSH:
10562                 return OP_X86_PUSH_IMM;
10563         case OP_X86_COMPARE_MEMBASE_REG:
10564                 return OP_X86_COMPARE_MEMBASE_IMM;
10565 #endif
10566 #if defined(TARGET_AMD64)
10567         case OP_AMD64_ICOMPARE_MEMBASE_REG:
10568                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10569 #endif
10570         case OP_VOIDCALL_REG:
10571                 return OP_VOIDCALL;
10572         case OP_CALL_REG:
10573                 return OP_CALL;
10574         case OP_LCALL_REG:
10575                 return OP_LCALL;
10576         case OP_FCALL_REG:
10577                 return OP_FCALL;
10578         case OP_LOCALLOC:
10579                 return OP_LOCALLOC_IMM;
10580         }
10581
10582         return -1;
10583 }
10584
10585 static int
10586 ldind_to_load_membase (int opcode)
10587 {
10588         switch (opcode) {
10589         case CEE_LDIND_I1:
10590                 return OP_LOADI1_MEMBASE;
10591         case CEE_LDIND_U1:
10592                 return OP_LOADU1_MEMBASE;
10593         case CEE_LDIND_I2:
10594                 return OP_LOADI2_MEMBASE;
10595         case CEE_LDIND_U2:
10596                 return OP_LOADU2_MEMBASE;
10597         case CEE_LDIND_I4:
10598                 return OP_LOADI4_MEMBASE;
10599         case CEE_LDIND_U4:
10600                 return OP_LOADU4_MEMBASE;
10601         case CEE_LDIND_I:
10602                 return OP_LOAD_MEMBASE;
10603         case CEE_LDIND_REF:
10604                 return OP_LOAD_MEMBASE;
10605         case CEE_LDIND_I8:
10606                 return OP_LOADI8_MEMBASE;
10607         case CEE_LDIND_R4:
10608                 return OP_LOADR4_MEMBASE;
10609         case CEE_LDIND_R8:
10610                 return OP_LOADR8_MEMBASE;
10611         default:
10612                 g_assert_not_reached ();
10613         }
10614
10615         return -1;
10616 }
10617
10618 static int
10619 stind_to_store_membase (int opcode)
10620 {
10621         switch (opcode) {
10622         case CEE_STIND_I1:
10623                 return OP_STOREI1_MEMBASE_REG;
10624         case CEE_STIND_I2:
10625                 return OP_STOREI2_MEMBASE_REG;
10626         case CEE_STIND_I4:
10627                 return OP_STOREI4_MEMBASE_REG;
10628         case CEE_STIND_I:
10629         case CEE_STIND_REF:
10630                 return OP_STORE_MEMBASE_REG;
10631         case CEE_STIND_I8:
10632                 return OP_STOREI8_MEMBASE_REG;
10633         case CEE_STIND_R4:
10634                 return OP_STORER4_MEMBASE_REG;
10635         case CEE_STIND_R8:
10636                 return OP_STORER8_MEMBASE_REG;
10637         default:
10638                 g_assert_not_reached ();
10639         }
10640
10641         return -1;
10642 }
10643
10644 int
10645 mono_load_membase_to_load_mem (int opcode)
10646 {
10647         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
10648 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10649         switch (opcode) {
10650         case OP_LOAD_MEMBASE:
10651                 return OP_LOAD_MEM;
10652         case OP_LOADU1_MEMBASE:
10653                 return OP_LOADU1_MEM;
10654         case OP_LOADU2_MEMBASE:
10655                 return OP_LOADU2_MEM;
10656         case OP_LOADI4_MEMBASE:
10657                 return OP_LOADI4_MEM;
10658         case OP_LOADU4_MEMBASE:
10659                 return OP_LOADU4_MEM;
10660 #if SIZEOF_REGISTER == 8
10661         case OP_LOADI8_MEMBASE:
10662                 return OP_LOADI8_MEM;
10663 #endif
10664         }
10665 #endif
10666
10667         return -1;
10668 }
10669
10670 static inline int
10671 op_to_op_dest_membase (int store_opcode, int opcode)
10672 {
10673 #if defined(TARGET_X86)
10674         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
10675                 return -1;
10676
10677         switch (opcode) {
10678         case OP_IADD:
10679                 return OP_X86_ADD_MEMBASE_REG;
10680         case OP_ISUB:
10681                 return OP_X86_SUB_MEMBASE_REG;
10682         case OP_IAND:
10683                 return OP_X86_AND_MEMBASE_REG;
10684         case OP_IOR:
10685                 return OP_X86_OR_MEMBASE_REG;
10686         case OP_IXOR:
10687                 return OP_X86_XOR_MEMBASE_REG;
10688         case OP_ADD_IMM:
10689         case OP_IADD_IMM:
10690                 return OP_X86_ADD_MEMBASE_IMM;
10691         case OP_SUB_IMM:
10692         case OP_ISUB_IMM:
10693                 return OP_X86_SUB_MEMBASE_IMM;
10694         case OP_AND_IMM:
10695         case OP_IAND_IMM:
10696                 return OP_X86_AND_MEMBASE_IMM;
10697         case OP_OR_IMM:
10698         case OP_IOR_IMM:
10699                 return OP_X86_OR_MEMBASE_IMM;
10700         case OP_XOR_IMM:
10701         case OP_IXOR_IMM:
10702                 return OP_X86_XOR_MEMBASE_IMM;
10703         case OP_MOVE:
10704                 return OP_NOP;
10705         }
10706 #endif
10707
10708 #if defined(TARGET_AMD64)
10709         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
10710                 return -1;
10711
10712         switch (opcode) {
10713         case OP_IADD:
10714                 return OP_X86_ADD_MEMBASE_REG;
10715         case OP_ISUB:
10716                 return OP_X86_SUB_MEMBASE_REG;
10717         case OP_IAND:
10718                 return OP_X86_AND_MEMBASE_REG;
10719         case OP_IOR:
10720                 return OP_X86_OR_MEMBASE_REG;
10721         case OP_IXOR:
10722                 return OP_X86_XOR_MEMBASE_REG;
10723         case OP_IADD_IMM:
10724                 return OP_X86_ADD_MEMBASE_IMM;
10725         case OP_ISUB_IMM:
10726                 return OP_X86_SUB_MEMBASE_IMM;
10727         case OP_IAND_IMM:
10728                 return OP_X86_AND_MEMBASE_IMM;
10729         case OP_IOR_IMM:
10730                 return OP_X86_OR_MEMBASE_IMM;
10731         case OP_IXOR_IMM:
10732                 return OP_X86_XOR_MEMBASE_IMM;
10733         case OP_LADD:
10734                 return OP_AMD64_ADD_MEMBASE_REG;
10735         case OP_LSUB:
10736                 return OP_AMD64_SUB_MEMBASE_REG;
10737         case OP_LAND:
10738                 return OP_AMD64_AND_MEMBASE_REG;
10739         case OP_LOR:
10740                 return OP_AMD64_OR_MEMBASE_REG;
10741         case OP_LXOR:
10742                 return OP_AMD64_XOR_MEMBASE_REG;
10743         case OP_ADD_IMM:
10744         case OP_LADD_IMM:
10745                 return OP_AMD64_ADD_MEMBASE_IMM;
10746         case OP_SUB_IMM:
10747         case OP_LSUB_IMM:
10748                 return OP_AMD64_SUB_MEMBASE_IMM;
10749         case OP_AND_IMM:
10750         case OP_LAND_IMM:
10751                 return OP_AMD64_AND_MEMBASE_IMM;
10752         case OP_OR_IMM:
10753         case OP_LOR_IMM:
10754                 return OP_AMD64_OR_MEMBASE_IMM;
10755         case OP_XOR_IMM:
10756         case OP_LXOR_IMM:
10757                 return OP_AMD64_XOR_MEMBASE_IMM;
10758         case OP_MOVE:
10759                 return OP_NOP;
10760         }
10761 #endif
10762
10763         return -1;
10764 }
10765
10766 static inline int
10767 op_to_op_store_membase (int store_opcode, int opcode)
10768 {
10769 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10770         switch (opcode) {
10771         case OP_ICEQ:
10772                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10773                         return OP_X86_SETEQ_MEMBASE;
10774         case OP_CNE:
10775                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10776                         return OP_X86_SETNE_MEMBASE;
10777         }
10778 #endif
10779
10780         return -1;
10781 }
10782
10783 static inline int
10784 op_to_op_src1_membase (int load_opcode, int opcode)
10785 {
10786 #ifdef TARGET_X86
10787         /* FIXME: This has sign extension issues */
10788         /*
10789         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10790                 return OP_X86_COMPARE_MEMBASE8_IMM;
10791         */
10792
10793         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10794                 return -1;
10795
10796         switch (opcode) {
10797         case OP_X86_PUSH:
10798                 return OP_X86_PUSH_MEMBASE;
10799         case OP_COMPARE_IMM:
10800         case OP_ICOMPARE_IMM:
10801                 return OP_X86_COMPARE_MEMBASE_IMM;
10802         case OP_COMPARE:
10803         case OP_ICOMPARE:
10804                 return OP_X86_COMPARE_MEMBASE_REG;
10805         }
10806 #endif
10807
10808 #ifdef TARGET_AMD64
10809         /* FIXME: This has sign extension issues */
10810         /*
10811         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10812                 return OP_X86_COMPARE_MEMBASE8_IMM;
10813         */
10814
10815         switch (opcode) {
10816         case OP_X86_PUSH:
10817                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10818                         return OP_X86_PUSH_MEMBASE;
10819                 break;
10820                 /* FIXME: This only works for 32 bit immediates
10821         case OP_COMPARE_IMM:
10822         case OP_LCOMPARE_IMM:
10823                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10824                         return OP_AMD64_COMPARE_MEMBASE_IMM;
10825                 */
10826         case OP_ICOMPARE_IMM:
10827                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10828                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10829                 break;
10830         case OP_COMPARE:
10831         case OP_LCOMPARE:
10832                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10833                         return OP_AMD64_COMPARE_MEMBASE_REG;
10834                 break;
10835         case OP_ICOMPARE:
10836                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10837                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
10838                 break;
10839         }
10840 #endif
10841
10842         return -1;
10843 }
10844
10845 static inline int
10846 op_to_op_src2_membase (int load_opcode, int opcode)
10847 {
10848 #ifdef TARGET_X86
10849         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10850                 return -1;
10851         
10852         switch (opcode) {
10853         case OP_COMPARE:
10854         case OP_ICOMPARE:
10855                 return OP_X86_COMPARE_REG_MEMBASE;
10856         case OP_IADD:
10857                 return OP_X86_ADD_REG_MEMBASE;
10858         case OP_ISUB:
10859                 return OP_X86_SUB_REG_MEMBASE;
10860         case OP_IAND:
10861                 return OP_X86_AND_REG_MEMBASE;
10862         case OP_IOR:
10863                 return OP_X86_OR_REG_MEMBASE;
10864         case OP_IXOR:
10865                 return OP_X86_XOR_REG_MEMBASE;
10866         }
10867 #endif
10868
10869 #ifdef TARGET_AMD64
10870         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
10871                 switch (opcode) {
10872                 case OP_ICOMPARE:
10873                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
10874                 case OP_IADD:
10875                         return OP_X86_ADD_REG_MEMBASE;
10876                 case OP_ISUB:
10877                         return OP_X86_SUB_REG_MEMBASE;
10878                 case OP_IAND:
10879                         return OP_X86_AND_REG_MEMBASE;
10880                 case OP_IOR:
10881                         return OP_X86_OR_REG_MEMBASE;
10882                 case OP_IXOR:
10883                         return OP_X86_XOR_REG_MEMBASE;
10884                 }
10885         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
10886                 switch (opcode) {
10887                 case OP_COMPARE:
10888                 case OP_LCOMPARE:
10889                         return OP_AMD64_COMPARE_REG_MEMBASE;
10890                 case OP_LADD:
10891                         return OP_AMD64_ADD_REG_MEMBASE;
10892                 case OP_LSUB:
10893                         return OP_AMD64_SUB_REG_MEMBASE;
10894                 case OP_LAND:
10895                         return OP_AMD64_AND_REG_MEMBASE;
10896                 case OP_LOR:
10897                         return OP_AMD64_OR_REG_MEMBASE;
10898                 case OP_LXOR:
10899                         return OP_AMD64_XOR_REG_MEMBASE;
10900                 }
10901         }
10902 #endif
10903
10904         return -1;
10905 }
10906
10907 int
10908 mono_op_to_op_imm_noemul (int opcode)
10909 {
10910         switch (opcode) {
10911 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
10912         case OP_LSHR:
10913         case OP_LSHL:
10914         case OP_LSHR_UN:
10915                 return -1;
10916 #endif
10917 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10918         case OP_IDIV:
10919         case OP_IDIV_UN:
10920         case OP_IREM:
10921         case OP_IREM_UN:
10922                 return -1;
10923 #endif
10924         default:
10925                 return mono_op_to_op_imm (opcode);
10926         }
10927 }
10928
10929 #ifndef DISABLE_JIT
10930
10931 /**
10932  * mono_handle_global_vregs:
10933  *
10934  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
10935  * for them.
10936  */
10937 void
10938 mono_handle_global_vregs (MonoCompile *cfg)
10939 {
10940         gint32 *vreg_to_bb;
10941         MonoBasicBlock *bb;
10942         int i, pos;
10943
10944         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
10945
10946 #ifdef MONO_ARCH_SIMD_INTRINSICS
10947         if (cfg->uses_simd_intrinsics)
10948                 mono_simd_simplify_indirection (cfg);
10949 #endif
10950
10951         /* Find local vregs used in more than one bb */
10952         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10953                 MonoInst *ins = bb->code;       
10954                 int block_num = bb->block_num;
10955
10956                 if (cfg->verbose_level > 2)
10957                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
10958
10959                 cfg->cbb = bb;
10960                 for (; ins; ins = ins->next) {
10961                         const char *spec = INS_INFO (ins->opcode);
10962                         int regtype = 0, regindex;
10963                         gint32 prev_bb;
10964
10965                         if (G_UNLIKELY (cfg->verbose_level > 2))
10966                                 mono_print_ins (ins);
10967
10968                         g_assert (ins->opcode >= MONO_CEE_LAST);
10969
10970                         for (regindex = 0; regindex < 4; regindex ++) {
10971                                 int vreg = 0;
10972
10973                                 if (regindex == 0) {
10974                                         regtype = spec [MONO_INST_DEST];
10975                                         if (regtype == ' ')
10976                                                 continue;
10977                                         vreg = ins->dreg;
10978                                 } else if (regindex == 1) {
10979                                         regtype = spec [MONO_INST_SRC1];
10980                                         if (regtype == ' ')
10981                                                 continue;
10982                                         vreg = ins->sreg1;
10983                                 } else if (regindex == 2) {
10984                                         regtype = spec [MONO_INST_SRC2];
10985                                         if (regtype == ' ')
10986                                                 continue;
10987                                         vreg = ins->sreg2;
10988                                 } else if (regindex == 3) {
10989                                         regtype = spec [MONO_INST_SRC3];
10990                                         if (regtype == ' ')
10991                                                 continue;
10992                                         vreg = ins->sreg3;
10993                                 }
10994
10995 #if SIZEOF_REGISTER == 4
10996                                 /* In the LLVM case, the long opcodes are not decomposed */
10997                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
10998                                         /*
10999                                          * Since some instructions reference the original long vreg,
11000                                          * and some reference the two component vregs, it is quite hard
11001                                          * to determine when it needs to be global. So be conservative.
11002                                          */
11003                                         if (!get_vreg_to_inst (cfg, vreg)) {
11004                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
11005
11006                                                 if (cfg->verbose_level > 2)
11007                                                         printf ("LONG VREG R%d made global.\n", vreg);
11008                                         }
11009
11010                                         /*
11011                                          * Make the component vregs volatile since the optimizations can
11012                                          * get confused otherwise.
11013                                          */
11014                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
11015                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
11016                                 }
11017 #endif
11018
11019                                 g_assert (vreg != -1);
11020
11021                                 prev_bb = vreg_to_bb [vreg];
11022                                 if (prev_bb == 0) {
11023                                         /* 0 is a valid block num */
11024                                         vreg_to_bb [vreg] = block_num + 1;
11025                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
11026                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
11027                                                 continue;
11028
11029                                         if (!get_vreg_to_inst (cfg, vreg)) {
11030                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11031                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
11032
11033                                                 switch (regtype) {
11034                                                 case 'i':
11035                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
11036                                                         break;
11037                                                 case 'l':
11038                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
11039                                                         break;
11040                                                 case 'f':
11041                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
11042                                                         break;
11043                                                 case 'v':
11044                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
11045                                                         break;
11046                                                 default:
11047                                                         g_assert_not_reached ();
11048                                                 }
11049                                         }
11050
11051                                         /* Flag as having been used in more than one bb */
11052                                         vreg_to_bb [vreg] = -1;
11053                                 }
11054                         }
11055                 }
11056         }
11057
11058         /* If a variable is used in only one bblock, convert it into a local vreg */
11059         for (i = 0; i < cfg->num_varinfo; i++) {
11060                 MonoInst *var = cfg->varinfo [i];
11061                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
11062
11063                 switch (var->type) {
11064                 case STACK_I4:
11065                 case STACK_OBJ:
11066                 case STACK_PTR:
11067                 case STACK_MP:
11068                 case STACK_VTYPE:
11069 #if SIZEOF_REGISTER == 8
11070                 case STACK_I8:
11071 #endif
11072 #if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
11073                 /* Enabling this screws up the fp stack on x86 */
11074                 case STACK_R8:
11075 #endif
11076                         /* Arguments are implicitly global */
11077                         /* Putting R4 vars into registers doesn't work currently */
11078                         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) {
11079                                 /* 
11080                                  * Make that the variable's liveness interval doesn't contain a call, since
11081                                  * that would cause the lvreg to be spilled, making the whole optimization
11082                                  * useless.
11083                                  */
11084                                 /* This is too slow for JIT compilation */
11085 #if 0
11086                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
11087                                         MonoInst *ins;
11088                                         int def_index, call_index, ins_index;
11089                                         gboolean spilled = FALSE;
11090
11091                                         def_index = -1;
11092                                         call_index = -1;
11093                                         ins_index = 0;
11094                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
11095                                                 const char *spec = INS_INFO (ins->opcode);
11096
11097                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
11098                                                         def_index = ins_index;
11099
11100                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
11101                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
11102                                                         if (call_index > def_index) {
11103                                                                 spilled = TRUE;
11104                                                                 break;
11105                                                         }
11106                                                 }
11107
11108                                                 if (MONO_IS_CALL (ins))
11109                                                         call_index = ins_index;
11110
11111                                                 ins_index ++;
11112                                         }
11113
11114                                         if (spilled)
11115                                                 break;
11116                                 }
11117 #endif
11118
11119                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11120                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
11121                                 var->flags |= MONO_INST_IS_DEAD;
11122                                 cfg->vreg_to_inst [var->dreg] = NULL;
11123                         }
11124                         break;
11125                 }
11126         }
11127
11128         /* 
11129          * Compress the varinfo and vars tables so the liveness computation is faster and
11130          * takes up less space.
11131          */
11132         pos = 0;
11133         for (i = 0; i < cfg->num_varinfo; ++i) {
11134                 MonoInst *var = cfg->varinfo [i];
11135                 if (pos < i && cfg->locals_start == i)
11136                         cfg->locals_start = pos;
11137                 if (!(var->flags & MONO_INST_IS_DEAD)) {
11138                         if (pos < i) {
11139                                 cfg->varinfo [pos] = cfg->varinfo [i];
11140                                 cfg->varinfo [pos]->inst_c0 = pos;
11141                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
11142                                 cfg->vars [pos].idx = pos;
11143 #if SIZEOF_REGISTER == 4
11144                                 if (cfg->varinfo [pos]->type == STACK_I8) {
11145                                         /* Modify the two component vars too */
11146                                         MonoInst *var1;
11147
11148                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
11149                                         var1->inst_c0 = pos;
11150                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
11151                                         var1->inst_c0 = pos;
11152                                 }
11153 #endif
11154                         }
11155                         pos ++;
11156                 }
11157         }
11158         cfg->num_varinfo = pos;
11159         if (cfg->locals_start > cfg->num_varinfo)
11160                 cfg->locals_start = cfg->num_varinfo;
11161 }
11162
11163 /**
11164  * mono_spill_global_vars:
11165  *
11166  *   Generate spill code for variables which are not allocated to registers, 
11167  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
11168  * code is generated which could be optimized by the local optimization passes.
11169  */
11170 void
11171 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
11172 {
11173         MonoBasicBlock *bb;
11174         char spec2 [16];
11175         int orig_next_vreg;
11176         guint32 *vreg_to_lvreg;
11177         guint32 *lvregs;
11178         guint32 i, lvregs_len;
11179         gboolean dest_has_lvreg = FALSE;
11180         guint32 stacktypes [128];
11181         MonoInst **live_range_start, **live_range_end;
11182         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
11183
11184         *need_local_opts = FALSE;
11185
11186         memset (spec2, 0, sizeof (spec2));
11187
11188         /* FIXME: Move this function to mini.c */
11189         stacktypes ['i'] = STACK_PTR;
11190         stacktypes ['l'] = STACK_I8;
11191         stacktypes ['f'] = STACK_R8;
11192 #ifdef MONO_ARCH_SIMD_INTRINSICS
11193         stacktypes ['x'] = STACK_VTYPE;
11194 #endif
11195
11196 #if SIZEOF_REGISTER == 4
11197         /* Create MonoInsts for longs */
11198         for (i = 0; i < cfg->num_varinfo; i++) {
11199                 MonoInst *ins = cfg->varinfo [i];
11200
11201                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
11202                         switch (ins->type) {
11203                         case STACK_R8:
11204                         case STACK_I8: {
11205                                 MonoInst *tree;
11206
11207                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
11208                                         break;
11209
11210                                 g_assert (ins->opcode == OP_REGOFFSET);
11211
11212                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
11213                                 g_assert (tree);
11214                                 tree->opcode = OP_REGOFFSET;
11215                                 tree->inst_basereg = ins->inst_basereg;
11216                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
11217
11218                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
11219                                 g_assert (tree);
11220                                 tree->opcode = OP_REGOFFSET;
11221                                 tree->inst_basereg = ins->inst_basereg;
11222                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
11223                                 break;
11224                         }
11225                         default:
11226                                 break;
11227                         }
11228                 }
11229         }
11230 #endif
11231
11232         /* FIXME: widening and truncation */
11233
11234         /*
11235          * As an optimization, when a variable allocated to the stack is first loaded into 
11236          * an lvreg, we will remember the lvreg and use it the next time instead of loading
11237          * the variable again.
11238          */
11239         orig_next_vreg = cfg->next_vreg;
11240         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
11241         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
11242         lvregs_len = 0;
11243
11244         /* 
11245          * These arrays contain the first and last instructions accessing a given
11246          * variable.
11247          * Since we emit bblocks in the same order we process them here, and we
11248          * don't split live ranges, these will precisely describe the live range of
11249          * the variable, i.e. the instruction range where a valid value can be found
11250          * in the variables location.
11251          * The live range is computed using the liveness info computed by the liveness pass.
11252          * We can't use vmv->range, since that is an abstract live range, and we need
11253          * one which is instruction precise.
11254          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
11255          */
11256         /* FIXME: Only do this if debugging info is requested */
11257         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
11258         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
11259         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
11260         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
11261         
11262         /* Add spill loads/stores */
11263         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11264                 MonoInst *ins;
11265
11266                 if (cfg->verbose_level > 2)
11267                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
11268
11269                 /* Clear vreg_to_lvreg array */
11270                 for (i = 0; i < lvregs_len; i++)
11271                         vreg_to_lvreg [lvregs [i]] = 0;
11272                 lvregs_len = 0;
11273
11274                 cfg->cbb = bb;
11275                 MONO_BB_FOR_EACH_INS (bb, ins) {
11276                         const char *spec = INS_INFO (ins->opcode);
11277                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
11278                         gboolean store, no_lvreg;
11279                         int sregs [MONO_MAX_SRC_REGS];
11280
11281                         if (G_UNLIKELY (cfg->verbose_level > 2))
11282                                 mono_print_ins (ins);
11283
11284                         if (ins->opcode == OP_NOP)
11285                                 continue;
11286
11287                         /* 
11288                          * We handle LDADDR here as well, since it can only be decomposed
11289                          * when variable addresses are known.
11290                          */
11291                         if (ins->opcode == OP_LDADDR) {
11292                                 MonoInst *var = ins->inst_p0;
11293
11294                                 if (var->opcode == OP_VTARG_ADDR) {
11295                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
11296                                         MonoInst *vtaddr = var->inst_left;
11297                                         if (vtaddr->opcode == OP_REGVAR) {
11298                                                 ins->opcode = OP_MOVE;
11299                                                 ins->sreg1 = vtaddr->dreg;
11300                                         }
11301                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
11302                                                 ins->opcode = OP_LOAD_MEMBASE;
11303                                                 ins->inst_basereg = vtaddr->inst_basereg;
11304                                                 ins->inst_offset = vtaddr->inst_offset;
11305                                         } else
11306                                                 NOT_IMPLEMENTED;
11307                                 } else {
11308                                         g_assert (var->opcode == OP_REGOFFSET);
11309
11310                                         ins->opcode = OP_ADD_IMM;
11311                                         ins->sreg1 = var->inst_basereg;
11312                                         ins->inst_imm = var->inst_offset;
11313                                 }
11314
11315                                 *need_local_opts = TRUE;
11316                                 spec = INS_INFO (ins->opcode);
11317                         }
11318
11319                         if (ins->opcode < MONO_CEE_LAST) {
11320                                 mono_print_ins (ins);
11321                                 g_assert_not_reached ();
11322                         }
11323
11324                         /*
11325                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
11326                          * src register.
11327                          * FIXME:
11328                          */
11329                         if (MONO_IS_STORE_MEMBASE (ins)) {
11330                                 tmp_reg = ins->dreg;
11331                                 ins->dreg = ins->sreg2;
11332                                 ins->sreg2 = tmp_reg;
11333                                 store = TRUE;
11334
11335                                 spec2 [MONO_INST_DEST] = ' ';
11336                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
11337                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
11338                                 spec2 [MONO_INST_SRC3] = ' ';
11339                                 spec = spec2;
11340                         } else if (MONO_IS_STORE_MEMINDEX (ins))
11341                                 g_assert_not_reached ();
11342                         else
11343                                 store = FALSE;
11344                         no_lvreg = FALSE;
11345
11346                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
11347                                 printf ("\t %.3s %d", spec, ins->dreg);
11348                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
11349                                 for (srcindex = 0; srcindex < 3; ++srcindex)
11350                                         printf (" %d", sregs [srcindex]);
11351                                 printf ("\n");
11352                         }
11353
11354                         /***************/
11355                         /*    DREG     */
11356                         /***************/
11357                         regtype = spec [MONO_INST_DEST];
11358                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
11359                         prev_dreg = -1;
11360
11361                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
11362                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
11363                                 MonoInst *store_ins;
11364                                 int store_opcode;
11365                                 MonoInst *def_ins = ins;
11366                                 int dreg = ins->dreg; /* The original vreg */
11367
11368                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
11369
11370                                 if (var->opcode == OP_REGVAR) {
11371                                         ins->dreg = var->dreg;
11372                                 } 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)) {
11373                                         /* 
11374                                          * Instead of emitting a load+store, use a _membase opcode.
11375                                          */
11376                                         g_assert (var->opcode == OP_REGOFFSET);
11377                                         if (ins->opcode == OP_MOVE) {
11378                                                 NULLIFY_INS (ins);
11379                                                 def_ins = NULL;
11380                                         } else {
11381                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
11382                                                 ins->inst_basereg = var->inst_basereg;
11383                                                 ins->inst_offset = var->inst_offset;
11384                                                 ins->dreg = -1;
11385                                         }
11386                                         spec = INS_INFO (ins->opcode);
11387                                 } else {
11388                                         guint32 lvreg;
11389
11390                                         g_assert (var->opcode == OP_REGOFFSET);
11391
11392                                         prev_dreg = ins->dreg;
11393
11394                                         /* Invalidate any previous lvreg for this vreg */
11395                                         vreg_to_lvreg [ins->dreg] = 0;
11396
11397                                         lvreg = 0;
11398
11399                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
11400                                                 regtype = 'l';
11401                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
11402                                         }
11403
11404                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
11405
11406                                         if (regtype == 'l') {
11407                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
11408                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
11409                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
11410                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
11411                                                 def_ins = store_ins;
11412                                         }
11413                                         else {
11414                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
11415
11416                                                 /* Try to fuse the store into the instruction itself */
11417                                                 /* FIXME: Add more instructions */
11418                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
11419                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
11420                                                         ins->inst_imm = ins->inst_c0;
11421                                                         ins->inst_destbasereg = var->inst_basereg;
11422                                                         ins->inst_offset = var->inst_offset;
11423                                                         spec = INS_INFO (ins->opcode);
11424                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
11425                                                         ins->opcode = store_opcode;
11426                                                         ins->inst_destbasereg = var->inst_basereg;
11427                                                         ins->inst_offset = var->inst_offset;
11428
11429                                                         no_lvreg = TRUE;
11430
11431                                                         tmp_reg = ins->dreg;
11432                                                         ins->dreg = ins->sreg2;
11433                                                         ins->sreg2 = tmp_reg;
11434                                                         store = TRUE;
11435
11436                                                         spec2 [MONO_INST_DEST] = ' ';
11437                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
11438                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
11439                                                         spec2 [MONO_INST_SRC3] = ' ';
11440                                                         spec = spec2;
11441                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
11442                                                         // FIXME: The backends expect the base reg to be in inst_basereg
11443                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
11444                                                         ins->dreg = -1;
11445                                                         ins->inst_basereg = var->inst_basereg;
11446                                                         ins->inst_offset = var->inst_offset;
11447                                                         spec = INS_INFO (ins->opcode);
11448                                                 } else {
11449                                                         /* printf ("INS: "); mono_print_ins (ins); */
11450                                                         /* Create a store instruction */
11451                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
11452
11453                                                         /* Insert it after the instruction */
11454                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
11455
11456                                                         def_ins = store_ins;
11457
11458                                                         /* 
11459                                                          * We can't assign ins->dreg to var->dreg here, since the
11460                                                          * sregs could use it. So set a flag, and do it after
11461                                                          * the sregs.
11462                                                          */
11463                                                         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)))
11464                                                                 dest_has_lvreg = TRUE;
11465                                                 }
11466                                         }
11467                                 }
11468
11469                                 if (def_ins && !live_range_start [dreg]) {
11470                                         live_range_start [dreg] = def_ins;
11471                                         live_range_start_bb [dreg] = bb;
11472                                 }
11473                         }
11474
11475                         /************/
11476                         /*  SREGS   */
11477                         /************/
11478                         num_sregs = mono_inst_get_src_registers (ins, sregs);
11479                         for (srcindex = 0; srcindex < 3; ++srcindex) {
11480                                 regtype = spec [MONO_INST_SRC1 + srcindex];
11481                                 sreg = sregs [srcindex];
11482
11483                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
11484                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
11485                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
11486                                         MonoInst *use_ins = ins;
11487                                         MonoInst *load_ins;
11488                                         guint32 load_opcode;
11489
11490                                         if (var->opcode == OP_REGVAR) {
11491                                                 sregs [srcindex] = var->dreg;
11492                                                 //mono_inst_set_src_registers (ins, sregs);
11493                                                 live_range_end [sreg] = use_ins;
11494                                                 live_range_end_bb [sreg] = bb;
11495                                                 continue;
11496                                         }
11497
11498                                         g_assert (var->opcode == OP_REGOFFSET);
11499                                                 
11500                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
11501
11502                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
11503
11504                                         if (vreg_to_lvreg [sreg]) {
11505                                                 g_assert (vreg_to_lvreg [sreg] != -1);
11506
11507                                                 /* The variable is already loaded to an lvreg */
11508                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11509                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
11510                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
11511                                                 //mono_inst_set_src_registers (ins, sregs);
11512                                                 continue;
11513                                         }
11514
11515                                         /* Try to fuse the load into the instruction */
11516                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
11517                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
11518                                                 sregs [0] = var->inst_basereg;
11519                                                 //mono_inst_set_src_registers (ins, sregs);
11520                                                 ins->inst_offset = var->inst_offset;
11521                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
11522                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
11523                                                 sregs [1] = var->inst_basereg;
11524                                                 //mono_inst_set_src_registers (ins, sregs);
11525                                                 ins->inst_offset = var->inst_offset;
11526                                         } else {
11527                                                 if (MONO_IS_REAL_MOVE (ins)) {
11528                                                         ins->opcode = OP_NOP;
11529                                                         sreg = ins->dreg;
11530                                                 } else {
11531                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
11532
11533                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
11534
11535                                                         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) {
11536                                                                 if (var->dreg == prev_dreg) {
11537                                                                         /*
11538                                                                          * sreg refers to the value loaded by the load
11539                                                                          * emitted below, but we need to use ins->dreg
11540                                                                          * since it refers to the store emitted earlier.
11541                                                                          */
11542                                                                         sreg = ins->dreg;
11543                                                                 }
11544                                                                 g_assert (sreg != -1);
11545                                                                 vreg_to_lvreg [var->dreg] = sreg;
11546                                                                 g_assert (lvregs_len < 1024);
11547                                                                 lvregs [lvregs_len ++] = var->dreg;
11548                                                         }
11549                                                 }
11550
11551                                                 sregs [srcindex] = sreg;
11552                                                 //mono_inst_set_src_registers (ins, sregs);
11553
11554                                                 if (regtype == 'l') {
11555                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
11556                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11557                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
11558                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11559                                                         use_ins = load_ins;
11560                                                 }
11561                                                 else {
11562 #if SIZEOF_REGISTER == 4
11563                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
11564 #endif
11565                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
11566                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11567                                                         use_ins = load_ins;
11568                                                 }
11569                                         }
11570
11571                                         if (var->dreg < orig_next_vreg) {
11572                                                 live_range_end [var->dreg] = use_ins;
11573                                                 live_range_end_bb [var->dreg] = bb;
11574                                         }
11575                                 }
11576                         }
11577                         mono_inst_set_src_registers (ins, sregs);
11578
11579                         if (dest_has_lvreg) {
11580                                 g_assert (ins->dreg != -1);
11581                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
11582                                 g_assert (lvregs_len < 1024);
11583                                 lvregs [lvregs_len ++] = prev_dreg;
11584                                 dest_has_lvreg = FALSE;
11585                         }
11586
11587                         if (store) {
11588                                 tmp_reg = ins->dreg;
11589                                 ins->dreg = ins->sreg2;
11590                                 ins->sreg2 = tmp_reg;
11591                         }
11592
11593                         if (MONO_IS_CALL (ins)) {
11594                                 /* Clear vreg_to_lvreg array */
11595                                 for (i = 0; i < lvregs_len; i++)
11596                                         vreg_to_lvreg [lvregs [i]] = 0;
11597                                 lvregs_len = 0;
11598                         } else if (ins->opcode == OP_NOP) {
11599                                 ins->dreg = -1;
11600                                 MONO_INST_NULLIFY_SREGS (ins);
11601                         }
11602
11603                         if (cfg->verbose_level > 2)
11604                                 mono_print_ins_index (1, ins);
11605                 }
11606
11607                 /* Extend the live range based on the liveness info */
11608                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
11609                         for (i = 0; i < cfg->num_varinfo; i ++) {
11610                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
11611
11612                                 if (vreg_is_volatile (cfg, vi->vreg))
11613                                         /* The liveness info is incomplete */
11614                                         continue;
11615
11616                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
11617                                         /* Live from at least the first ins of this bb */
11618                                         live_range_start [vi->vreg] = bb->code;
11619                                         live_range_start_bb [vi->vreg] = bb;
11620                                 }
11621
11622                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
11623                                         /* Live at least until the last ins of this bb */
11624                                         live_range_end [vi->vreg] = bb->last_ins;
11625                                         live_range_end_bb [vi->vreg] = bb;
11626                                 }
11627                         }
11628                 }
11629         }
11630         
11631 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
11632         /*
11633          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
11634          * by storing the current native offset into MonoMethodVar->live_range_start/end.
11635          */
11636         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
11637                 for (i = 0; i < cfg->num_varinfo; ++i) {
11638                         int vreg = MONO_VARINFO (cfg, i)->vreg;
11639                         MonoInst *ins;
11640
11641                         if (live_range_start [vreg]) {
11642                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
11643                                 ins->inst_c0 = i;
11644                                 ins->inst_c1 = vreg;
11645                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
11646                         }
11647                         if (live_range_end [vreg]) {
11648                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
11649                                 ins->inst_c0 = i;
11650                                 ins->inst_c1 = vreg;
11651                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
11652                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
11653                                 else
11654                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
11655                         }
11656                 }
11657         }
11658 #endif
11659
11660         g_free (live_range_start);
11661         g_free (live_range_end);
11662         g_free (live_range_start_bb);
11663         g_free (live_range_end_bb);
11664 }
11665
11666 /**
11667  * FIXME:
11668  * - use 'iadd' instead of 'int_add'
11669  * - handling ovf opcodes: decompose in method_to_ir.
11670  * - unify iregs/fregs
11671  *   -> partly done, the missing parts are:
11672  *   - a more complete unification would involve unifying the hregs as well, so
11673  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
11674  *     would no longer map to the machine hregs, so the code generators would need to
11675  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
11676  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
11677  *     fp/non-fp branches speeds it up by about 15%.
11678  * - use sext/zext opcodes instead of shifts
11679  * - add OP_ICALL
11680  * - get rid of TEMPLOADs if possible and use vregs instead
11681  * - clean up usage of OP_P/OP_ opcodes
11682  * - cleanup usage of DUMMY_USE
11683  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
11684  *   stack
11685  * - set the stack type and allocate a dreg in the EMIT_NEW macros
11686  * - get rid of all the <foo>2 stuff when the new JIT is ready.
11687  * - make sure handle_stack_args () is called before the branch is emitted
11688  * - when the new IR is done, get rid of all unused stuff
11689  * - COMPARE/BEQ as separate instructions or unify them ?
11690  *   - keeping them separate allows specialized compare instructions like
11691  *     compare_imm, compare_membase
11692  *   - most back ends unify fp compare+branch, fp compare+ceq
11693  * - integrate mono_save_args into inline_method
11694  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
11695  * - handle long shift opts on 32 bit platforms somehow: they require 
11696  *   3 sregs (2 for arg1 and 1 for arg2)
11697  * - make byref a 'normal' type.
11698  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
11699  *   variable if needed.
11700  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
11701  *   like inline_method.
11702  * - remove inlining restrictions
11703  * - fix LNEG and enable cfold of INEG
11704  * - generalize x86 optimizations like ldelema as a peephole optimization
11705  * - add store_mem_imm for amd64
11706  * - optimize the loading of the interruption flag in the managed->native wrappers
11707  * - avoid special handling of OP_NOP in passes
11708  * - move code inserting instructions into one function/macro.
11709  * - try a coalescing phase after liveness analysis
11710  * - add float -> vreg conversion + local optimizations on !x86
11711  * - figure out how to handle decomposed branches during optimizations, ie.
11712  *   compare+branch, op_jump_table+op_br etc.
11713  * - promote RuntimeXHandles to vregs
11714  * - vtype cleanups:
11715  *   - add a NEW_VARLOADA_VREG macro
11716  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
11717  *   accessing vtype fields.
11718  * - get rid of I8CONST on 64 bit platforms
11719  * - dealing with the increase in code size due to branches created during opcode
11720  *   decomposition:
11721  *   - use extended basic blocks
11722  *     - all parts of the JIT
11723  *     - handle_global_vregs () && local regalloc
11724  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
11725  * - sources of increase in code size:
11726  *   - vtypes
11727  *   - long compares
11728  *   - isinst and castclass
11729  *   - lvregs not allocated to global registers even if used multiple times
11730  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
11731  *   meaningful.
11732  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
11733  * - add all micro optimizations from the old JIT
11734  * - put tree optimizations into the deadce pass
11735  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
11736  *   specific function.
11737  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
11738  *   fcompare + branchCC.
11739  * - create a helper function for allocating a stack slot, taking into account 
11740  *   MONO_CFG_HAS_SPILLUP.
11741  * - merge r68207.
11742  * - merge the ia64 switch changes.
11743  * - optimize mono_regstate2_alloc_int/float.
11744  * - fix the pessimistic handling of variables accessed in exception handler blocks.
11745  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
11746  *   parts of the tree could be separated by other instructions, killing the tree
11747  *   arguments, or stores killing loads etc. Also, should we fold loads into other
11748  *   instructions if the result of the load is used multiple times ?
11749  * - make the REM_IMM optimization in mini-x86.c arch-independent.
11750  * - LAST MERGE: 108395.
11751  * - when returning vtypes in registers, generate IR and append it to the end of the
11752  *   last bb instead of doing it in the epilog.
11753  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
11754  */
11755
11756 /*
11757
11758 NOTES
11759 -----
11760
11761 - When to decompose opcodes:
11762   - earlier: this makes some optimizations hard to implement, since the low level IR
11763   no longer contains the neccessary information. But it is easier to do.
11764   - later: harder to implement, enables more optimizations.
11765 - Branches inside bblocks:
11766   - created when decomposing complex opcodes. 
11767     - branches to another bblock: harmless, but not tracked by the branch 
11768       optimizations, so need to branch to a label at the start of the bblock.
11769     - branches to inside the same bblock: very problematic, trips up the local
11770       reg allocator. Can be fixed by spitting the current bblock, but that is a
11771       complex operation, since some local vregs can become global vregs etc.
11772 - Local/global vregs:
11773   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
11774     local register allocator.
11775   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
11776     structure, created by mono_create_var (). Assigned to hregs or the stack by
11777     the global register allocator.
11778 - When to do optimizations like alu->alu_imm:
11779   - earlier -> saves work later on since the IR will be smaller/simpler
11780   - later -> can work on more instructions
11781 - Handling of valuetypes:
11782   - When a vtype is pushed on the stack, a new temporary is created, an 
11783     instruction computing its address (LDADDR) is emitted and pushed on
11784     the stack. Need to optimize cases when the vtype is used immediately as in
11785     argument passing, stloc etc.
11786 - Instead of the to_end stuff in the old JIT, simply call the function handling
11787   the values on the stack before emitting the last instruction of the bb.
11788 */
11789
11790 #endif /* DISABLE_JIT */