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