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