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