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