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