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