2009-09-25 Mark Probst <mark.probst@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
4912                                                 g_assert (vtable); /*This shall not fail since we check for this condition on OP_NEWARR creation*/
4913                                                 NEW_VTABLECONST (cfg, iargs [0], vtable);
4914                                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
4915                                                 MONO_INST_NEW (cfg, iargs [1], OP_MOVE);
4916                                                 iargs [1]->dreg = ins->sreg1;
4917
4918                                                 dest = mono_emit_jit_icall (cfg, mono_array_new_specific, iargs);
4919                                                 dest->dreg = ins->dreg;
4920                                         }
4921                                         break;
4922                                 case OP_STRLEN:
4923                                         NEW_LOAD_MEMBASE (cfg, dest, OP_LOADI4_MEMBASE, ins->dreg,
4924                                                                           ins->sreg1, G_STRUCT_OFFSET (MonoString, length));
4925                                         MONO_ADD_INS (cfg->cbb, dest);
4926                                         break;
4927                                 default:
4928                                         break;
4929                                 }
4930
4931                                 g_assert (cfg->cbb == first_bb);
4932
4933                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
4934                                         /* Replace the original instruction with the new code sequence */
4935
4936                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
4937                                         first_bb->code = first_bb->last_ins = NULL;
4938                                         first_bb->in_count = first_bb->out_count = 0;
4939                                         cfg->cbb = first_bb;
4940                                 }
4941                                 else
4942                                         prev = ins;
4943                         }
4944                 }
4945
4946                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER DECOMPOSE-ARRAY-ACCESS-OPTS ");
4947         }
4948 }
4949
4950 typedef union {
4951         guint32 vali [2];
4952         gint64 vall;
4953         double vald;
4954 } DVal;
4955
4956 #ifdef MONO_ARCH_SOFT_FLOAT
4957
4958 /**
4959  * mono_decompose_soft_float:
4960  *
4961  *  Soft float support on ARM. We store each double value in a pair of integer vregs,
4962  * similar to long support on 32 bit platforms. 32 bit float values require special
4963  * handling when used as locals, arguments, and in calls.
4964  * One big problem with soft-float is that there are few r4 test cases in our test suite.
4965  */
4966 void
4967 mono_decompose_soft_float (MonoCompile *cfg)
4968 {
4969         MonoBasicBlock *bb, *first_bb;
4970
4971         /*
4972          * This pass creates long opcodes, so it should be run before decompose_long_opts ().
4973          */
4974
4975         /**
4976          * Create a dummy bblock and emit code into it so we can use the normal 
4977          * code generation macros.
4978          */
4979         cfg->cbb = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoBasicBlock));
4980         first_bb = cfg->cbb;
4981
4982         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4983                 MonoInst *ins;
4984                 MonoInst *prev = NULL;
4985                 gboolean restart;
4986
4987                 if (cfg->verbose_level > 3) mono_print_bb (bb, "BEFORE HANDLE-SOFT-FLOAT ");
4988
4989                 cfg->cbb->code = cfg->cbb->last_ins = NULL;
4990                 restart = TRUE;
4991
4992                 while (restart) {
4993                         restart = FALSE;
4994
4995                         for (ins = bb->code; ins; ins = ins->next) {
4996                                 const char *spec = INS_INFO (ins->opcode);
4997
4998                                 /* Most fp operations are handled automatically by opcode emulation */
4999
5000                                 switch (ins->opcode) {
5001                                 case OP_R8CONST: {
5002                                         DVal d;
5003                                         d.vald = *(double*)ins->inst_p0;
5004                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
5005                                         break;
5006                                 }
5007                                 case OP_R4CONST: {
5008                                         DVal d;
5009                                         /* We load the r8 value */
5010                                         d.vald = *(float*)ins->inst_p0;
5011                                         MONO_EMIT_NEW_I8CONST (cfg, ins->dreg, d.vall);
5012                                         break;
5013                                 }
5014                                 case OP_FMOVE:
5015                                         ins->opcode = OP_LMOVE;
5016                                         break;
5017                                 case OP_FGETLOW32:
5018                                         ins->opcode = OP_MOVE;
5019                                         ins->sreg1 = ins->sreg1 + 1;
5020                                         break;
5021                                 case OP_FGETHIGH32:
5022                                         ins->opcode = OP_MOVE;
5023                                         ins->sreg1 = ins->sreg1 + 2;
5024                                         break;
5025                                 case OP_SETFRET: {
5026                                         int reg = ins->sreg1;
5027
5028                                         ins->opcode = OP_SETLRET;
5029                                         ins->dreg = -1;
5030                                         ins->sreg1 = reg + 1;
5031                                         ins->sreg2 = reg + 2;
5032                                         break;
5033                                 }
5034                                 case OP_LOADR8_MEMBASE:
5035                                         ins->opcode = OP_LOADI8_MEMBASE;
5036                                         break;
5037                                 case OP_STORER8_MEMBASE_REG:
5038                                         ins->opcode = OP_STOREI8_MEMBASE_REG;
5039                                         break;
5040                                 case OP_STORER4_MEMBASE_REG: {
5041                                         MonoInst *iargs [2];
5042                                         int addr_reg;
5043
5044                                         /* Arg 1 is the double value */
5045                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
5046                                         iargs [0]->dreg = ins->sreg1;
5047
5048                                         /* Arg 2 is the address to store to */
5049                                         addr_reg = mono_alloc_preg (cfg);
5050                                         EMIT_NEW_BIALU_IMM (cfg, iargs [1], OP_PADD_IMM, addr_reg, ins->inst_destbasereg, ins->inst_offset);
5051                                         mono_emit_jit_icall (cfg, mono_fstore_r4, iargs);
5052                                         restart = TRUE;
5053                                         break;
5054                                 }
5055                                 case OP_LOADR4_MEMBASE: {
5056                                         MonoInst *iargs [1];
5057                                         MonoInst *conv;
5058                                         int addr_reg;
5059
5060                                         addr_reg = mono_alloc_preg (cfg);
5061                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, addr_reg, ins->inst_basereg, ins->inst_offset);
5062                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
5063                                         conv->dreg = ins->dreg;
5064                                         break;
5065                                 }                                       
5066                                 case OP_FCALL:
5067                                 case OP_FCALL_REG:
5068                                 case OP_FCALL_MEMBASE: {
5069                                         MonoCallInst *call = (MonoCallInst*)ins;
5070                                         if (call->signature->ret->type == MONO_TYPE_R4) {
5071                                                 MonoCallInst *call2;
5072                                                 MonoInst *iargs [1];
5073                                                 MonoInst *conv;
5074
5075                                                 /* Convert the call into a call returning an int */
5076                                                 MONO_INST_NEW_CALL (cfg, call2, OP_CALL);
5077                                                 memcpy (call2, call, sizeof (MonoCallInst));
5078                                                 switch (ins->opcode) {
5079                                                 case OP_FCALL:
5080                                                         call2->inst.opcode = OP_CALL;
5081                                                         break;
5082                                                 case OP_FCALL_REG:
5083                                                         call2->inst.opcode = OP_CALL_REG;
5084                                                         break;
5085                                                 case OP_FCALL_MEMBASE:
5086                                                         call2->inst.opcode = OP_CALL_MEMBASE;
5087                                                         break;
5088                                                 default:
5089                                                         g_assert_not_reached ();
5090                                                 }
5091                                                 call2->inst.dreg = mono_alloc_ireg (cfg);
5092                                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call2);
5093
5094                                                 /* FIXME: Optimize this */
5095
5096                                                 /* Emit an r4->r8 conversion */
5097                                                 EMIT_NEW_VARLOADA_VREG (cfg, iargs [0], call2->inst.dreg, &mono_defaults.int32_class->byval_arg);
5098                                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4, iargs);
5099                                                 conv->dreg = ins->dreg;
5100                                         } else {
5101                                                 switch (ins->opcode) {
5102                                                 case OP_FCALL:
5103                                                         ins->opcode = OP_LCALL;
5104                                                         break;
5105                                                 case OP_FCALL_REG:
5106                                                         ins->opcode = OP_LCALL_REG;
5107                                                         break;
5108                                                 case OP_FCALL_MEMBASE:
5109                                                         ins->opcode = OP_LCALL_MEMBASE;
5110                                                         break;
5111                                                 default:
5112                                                         g_assert_not_reached ();
5113                                                 }
5114                                         }
5115                                         break;
5116                                 }
5117                                 case OP_FCOMPARE: {
5118                                         MonoJitICallInfo *info;
5119                                         MonoInst *iargs [2];
5120                                         MonoInst *call, *cmp, *br;
5121
5122                                         /* Convert fcompare+fbcc to icall+icompare+beq */
5123
5124                                         info = mono_find_jit_opcode_emulation (ins->next->opcode);
5125                                         g_assert (info);
5126
5127                                         /* Create dummy MonoInst's for the arguments */
5128                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
5129                                         iargs [0]->dreg = ins->sreg1;
5130                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
5131                                         iargs [1]->dreg = ins->sreg2;
5132
5133                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
5134
5135                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
5136                                         cmp->sreg1 = call->dreg;
5137                                         cmp->inst_imm = 0;
5138                                         MONO_ADD_INS (cfg->cbb, cmp);
5139                                         
5140                                         MONO_INST_NEW (cfg, br, OP_IBNE_UN);
5141                                         br->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * 2);
5142                                         br->inst_true_bb = ins->next->inst_true_bb;
5143                                         br->inst_false_bb = ins->next->inst_false_bb;
5144                                         MONO_ADD_INS (cfg->cbb, br);
5145
5146                                         /* The call sequence might include fp ins */
5147                                         restart = TRUE;
5148
5149                                         /* Skip fbcc or fccc */
5150                                         NULLIFY_INS (ins->next);
5151                                         break;
5152                                 }
5153                                 case OP_FCEQ:
5154                                 case OP_FCGT:
5155                                 case OP_FCGT_UN:
5156                                 case OP_FCLT:
5157                                 case OP_FCLT_UN: {
5158                                         MonoJitICallInfo *info;
5159                                         MonoInst *iargs [2];
5160                                         MonoInst *call;
5161
5162                                         /* Convert fccc to icall+icompare+iceq */
5163
5164                                         info = mono_find_jit_opcode_emulation (ins->opcode);
5165                                         g_assert (info);
5166
5167                                         /* Create dummy MonoInst's for the arguments */
5168                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
5169                                         iargs [0]->dreg = ins->sreg1;
5170                                         MONO_INST_NEW (cfg, iargs [1], OP_ARG);
5171                                         iargs [1]->dreg = ins->sreg2;
5172
5173                                         call = mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, iargs);
5174
5175                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, call->dreg, 1);
5176                                         MONO_EMIT_NEW_UNALU (cfg, OP_ICEQ, ins->dreg, -1);
5177
5178                                         /* The call sequence might include fp ins */
5179                                         restart = TRUE;
5180                                         break;
5181                                 }
5182                                 case OP_CKFINITE: {
5183                                         MonoInst *iargs [2];
5184                                         MonoInst *call, *cmp;
5185
5186                                         /* Convert to icall+icompare+cond_exc+move */
5187
5188                                         /* Create dummy MonoInst's for the arguments */
5189                                         MONO_INST_NEW (cfg, iargs [0], OP_ARG);
5190                                         iargs [0]->dreg = ins->sreg1;
5191
5192                                         call = mono_emit_jit_icall (cfg, mono_isfinite, iargs);
5193
5194                                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE_IMM);
5195                                         cmp->sreg1 = call->dreg;
5196                                         cmp->inst_imm = 1;
5197                                         MONO_ADD_INS (cfg->cbb, cmp);
5198
5199                                         MONO_EMIT_NEW_COND_EXC (cfg, INE_UN, "ArithmeticException");
5200
5201                                         /* Do the assignment if the value is finite */
5202                                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, ins->dreg, ins->sreg1);
5203
5204                                         restart = TRUE;
5205                                         break;
5206                                 }
5207                                 default:
5208                                         if (spec [MONO_INST_SRC1] == 'f' || spec [MONO_INST_SRC2] == 'f' || spec [MONO_INST_DEST] == 'f') {
5209                                                 mono_print_ins (ins);
5210                                                 g_assert_not_reached ();
5211                                         }
5212                                         break;
5213                                 }
5214
5215                                 g_assert (cfg->cbb == first_bb);
5216
5217                                 if (cfg->cbb->code || (cfg->cbb != first_bb)) {
5218                                         /* Replace the original instruction with the new code sequence */
5219
5220                                         mono_replace_ins (cfg, bb, ins, &prev, first_bb, cfg->cbb);
5221                                         first_bb->code = first_bb->last_ins = NULL;
5222                                         first_bb->in_count = first_bb->out_count = 0;
5223                                         cfg->cbb = first_bb;
5224                                 }
5225                                 else
5226                                         prev = ins;
5227                         }
5228                 }
5229
5230                 if (cfg->verbose_level > 3) mono_print_bb (bb, "AFTER HANDLE-SOFT-FLOAT ");
5231         }
5232
5233         mono_decompose_long_opts (cfg);
5234 }
5235
5236 #endif
5237
5238 static void
5239 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
5240 {
5241         MonoInst *ins;
5242         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
5243         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
5244                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
5245                 /* Optimize reg-reg moves away */
5246                 /* 
5247                  * Can't optimize other opcodes, since sp[0] might point to
5248                  * the last ins of a decomposed opcode.
5249                  */
5250                 sp [0]->dreg = (cfg)->locals [n]->dreg;
5251         } else {
5252                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
5253         }
5254 }
5255
5256 /*
5257  * ldloca inhibits many optimizations so try to get rid of it in common
5258  * cases.
5259  */
5260 static inline unsigned char *
5261 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
5262 {
5263         int local, token;
5264         MonoClass *klass;
5265
5266         if (size == 1) {
5267                 local = ip [1];
5268                 ip += 2;
5269         } else {
5270                 local = read16 (ip + 2);
5271                 ip += 4;
5272         }
5273         
5274         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
5275                 gboolean skip = FALSE;
5276
5277                 /* From the INITOBJ case */
5278                 token = read32 (ip + 2);
5279                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
5280                 CHECK_TYPELOAD (klass);
5281                 if (generic_class_is_reference_type (cfg, klass)) {
5282                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5283                 } else if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5284                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5285                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
5286                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [local]->dreg, klass);
5287                 } else {
5288                         skip = TRUE;
5289                 }
5290                         
5291                 if (!skip)
5292                         return ip + 6;
5293         }
5294 load_error:
5295         return NULL;
5296 }
5297
5298 static gboolean
5299 is_exception_class (MonoClass *class)
5300 {
5301         while (class) {
5302                 if (class == mono_defaults.exception_class)
5303                         return TRUE;
5304                 class = class->parent;
5305         }
5306         return FALSE;
5307 }
5308
5309 /*
5310  * mono_method_to_ir:
5311  *
5312  *   Translate the .net IL into linear IR.
5313  */
5314 int
5315 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5316                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5317                    guint inline_offset, gboolean is_virtual_call)
5318 {
5319         MonoInst *ins, **sp, **stack_start;
5320         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5321         MonoMethod *cmethod, *method_definition;
5322         MonoInst **arg_array;
5323         MonoMethodHeader *header;
5324         MonoImage *image;
5325         guint32 token, ins_flag;
5326         MonoClass *klass;
5327         MonoClass *constrained_call = NULL;
5328         unsigned char *ip, *end, *target, *err_pos;
5329         static double r8_0 = 0.0;
5330         MonoMethodSignature *sig;
5331         MonoGenericContext *generic_context = NULL;
5332         MonoGenericContainer *generic_container = NULL;
5333         MonoType **param_types;
5334         int i, n, start_new_bblock, dreg;
5335         int num_calls = 0, inline_costs = 0;
5336         int breakpoint_id = 0;
5337         guint num_args;
5338         MonoBoolean security, pinvoke;
5339         MonoSecurityManager* secman = NULL;
5340         MonoDeclSecurityActions actions;
5341         GSList *class_inits = NULL;
5342         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5343         int context_used;
5344         gboolean init_locals;
5345
5346         /* serialization and xdomain stuff may need access to private fields and methods */
5347         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5348         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5349         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5350         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5351         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5352         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5353
5354         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5355
5356         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5357         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5358         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5359         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5360
5361         image = method->klass->image;
5362         header = mono_method_get_header (method);
5363         generic_container = mono_method_get_generic_container (method);
5364         sig = mono_method_signature (method);
5365         num_args = sig->hasthis + sig->param_count;
5366         ip = (unsigned char*)header->code;
5367         cfg->cil_start = ip;
5368         end = ip + header->code_size;
5369         mono_jit_stats.cil_code_size += header->code_size;
5370         init_locals = header->init_locals;
5371
5372         /* 
5373          * Methods without init_locals set could cause asserts in various passes
5374          * (#497220).
5375          */
5376         init_locals = TRUE;
5377
5378         method_definition = method;
5379         while (method_definition->is_inflated) {
5380                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5381                 method_definition = imethod->declaring;
5382         }
5383
5384         /* SkipVerification is not allowed if core-clr is enabled */
5385         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5386                 dont_verify = TRUE;
5387                 dont_verify_stloc = TRUE;
5388         }
5389
5390         if (!dont_verify && mini_method_verify (cfg, method_definition))
5391                 goto exception_exit;
5392
5393         if (mono_debug_using_mono_debugger ())
5394                 cfg->keep_cil_nops = TRUE;
5395
5396         if (sig->is_inflated)
5397                 generic_context = mono_method_get_context (method);
5398         else if (generic_container)
5399                 generic_context = &generic_container->context;
5400         cfg->generic_context = generic_context;
5401
5402         if (!cfg->generic_sharing_context)
5403                 g_assert (!sig->has_type_parameters);
5404
5405         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5406                 g_assert (method->is_inflated);
5407                 g_assert (mono_method_get_context (method)->method_inst);
5408         }
5409         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5410                 g_assert (sig->generic_param_count);
5411
5412         if (cfg->method == method) {
5413                 cfg->real_offset = 0;
5414         } else {
5415                 cfg->real_offset = inline_offset;
5416         }
5417
5418         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5419         cfg->cil_offset_to_bb_len = header->code_size;
5420
5421         cfg->current_method = method;
5422
5423         if (cfg->verbose_level > 2)
5424                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
5425
5426         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5427         if (sig->hasthis)
5428                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5429         for (n = 0; n < sig->param_count; ++n)
5430                 param_types [n + sig->hasthis] = sig->params [n];
5431         cfg->arg_types = param_types;
5432
5433         dont_inline = g_list_prepend (dont_inline, method);
5434         if (cfg->method == method) {
5435
5436                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5437                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5438
5439                 /* ENTRY BLOCK */
5440                 NEW_BBLOCK (cfg, start_bblock);
5441                 cfg->bb_entry = start_bblock;
5442                 start_bblock->cil_code = NULL;
5443                 start_bblock->cil_length = 0;
5444
5445                 /* EXIT BLOCK */
5446                 NEW_BBLOCK (cfg, end_bblock);
5447                 cfg->bb_exit = end_bblock;
5448                 end_bblock->cil_code = NULL;
5449                 end_bblock->cil_length = 0;
5450                 g_assert (cfg->num_bblocks == 2);
5451
5452                 arg_array = cfg->args;
5453
5454                 if (header->num_clauses) {
5455                         cfg->spvars = g_hash_table_new (NULL, NULL);
5456                         cfg->exvars = g_hash_table_new (NULL, NULL);
5457                 }
5458                 /* handle exception clauses */
5459                 for (i = 0; i < header->num_clauses; ++i) {
5460                         MonoBasicBlock *try_bb;
5461                         MonoExceptionClause *clause = &header->clauses [i];
5462                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5463                         try_bb->real_offset = clause->try_offset;
5464                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5465                         tblock->real_offset = clause->handler_offset;
5466                         tblock->flags |= BB_EXCEPTION_HANDLER;
5467
5468                         link_bblock (cfg, try_bb, tblock);
5469
5470                         if (*(ip + clause->handler_offset) == CEE_POP)
5471                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5472
5473                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5474                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5475                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5476                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5477                                 MONO_ADD_INS (tblock, ins);
5478
5479                                 /* todo: is a fault block unsafe to optimize? */
5480                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5481                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5482                         }
5483
5484
5485                         /*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);
5486                           while (p < end) {
5487                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
5488                           }*/
5489                         /* catch and filter blocks get the exception object on the stack */
5490                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5491                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5492                                 MonoInst *dummy_use;
5493
5494                                 /* mostly like handle_stack_args (), but just sets the input args */
5495                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
5496                                 tblock->in_scount = 1;
5497                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5498                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5499
5500                                 /* 
5501                                  * Add a dummy use for the exvar so its liveness info will be
5502                                  * correct.
5503                                  */
5504                                 cfg->cbb = tblock;
5505                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
5506                                 
5507                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5508                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5509                                         tblock->flags |= BB_EXCEPTION_HANDLER;
5510                                         tblock->real_offset = clause->data.filter_offset;
5511                                         tblock->in_scount = 1;
5512                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5513                                         /* The filter block shares the exvar with the handler block */
5514                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5515                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5516                                         MONO_ADD_INS (tblock, ins);
5517                                 }
5518                         }
5519
5520                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5521                                         clause->data.catch_class &&
5522                                         cfg->generic_sharing_context &&
5523                                         mono_class_check_context_used (clause->data.catch_class)) {
5524                                 /*
5525                                  * In shared generic code with catch
5526                                  * clauses containing type variables
5527                                  * the exception handling code has to
5528                                  * be able to get to the rgctx.
5529                                  * Therefore we have to make sure that
5530                                  * the vtable/mrgctx argument (for
5531                                  * static or generic methods) or the
5532                                  * "this" argument (for non-static
5533                                  * methods) are live.
5534                                  */
5535                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5536                                                 mini_method_get_context (method)->method_inst ||
5537                                                 method->klass->valuetype) {
5538                                         mono_get_vtable_var (cfg);
5539                                 } else {
5540                                         MonoInst *dummy_use;
5541
5542                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
5543                                 }
5544                         }
5545                 }
5546         } else {
5547                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
5548                 cfg->cbb = start_bblock;
5549                 cfg->args = arg_array;
5550                 mono_save_args (cfg, sig, inline_args);
5551         }
5552
5553         /* FIRST CODE BLOCK */
5554         NEW_BBLOCK (cfg, bblock);
5555         bblock->cil_code = ip;
5556         cfg->cbb = bblock;
5557         cfg->ip = ip;
5558
5559         ADD_BBLOCK (cfg, bblock);
5560
5561         if (cfg->method == method) {
5562                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5563                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5564                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5565                         MONO_ADD_INS (bblock, ins);
5566                 }
5567         }
5568
5569         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5570                 secman = mono_security_manager_get_methods ();
5571
5572         security = (secman && mono_method_has_declsec (method));
5573         /* at this point having security doesn't mean we have any code to generate */
5574         if (security && (cfg->method == method)) {
5575                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5576                  * And we do not want to enter the next section (with allocation) if we
5577                  * have nothing to generate */
5578                 security = mono_declsec_get_demands (method, &actions);
5579         }
5580
5581         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5582         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5583         if (pinvoke) {
5584                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5585                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5586                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5587
5588                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5589                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5590                                 pinvoke = FALSE;
5591                         }
5592                         if (custom)
5593                                 mono_custom_attrs_free (custom);
5594
5595                         if (pinvoke) {
5596                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5597                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5598                                         pinvoke = FALSE;
5599                                 }
5600                                 if (custom)
5601                                         mono_custom_attrs_free (custom);
5602                         }
5603                 } else {
5604                         /* not a P/Invoke after all */
5605                         pinvoke = FALSE;
5606                 }
5607         }
5608         
5609         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5610                 /* we use a separate basic block for the initialization code */
5611                 NEW_BBLOCK (cfg, init_localsbb);
5612                 cfg->bb_init = init_localsbb;
5613                 init_localsbb->real_offset = cfg->real_offset;
5614                 start_bblock->next_bb = init_localsbb;
5615                 init_localsbb->next_bb = bblock;
5616                 link_bblock (cfg, start_bblock, init_localsbb);
5617                 link_bblock (cfg, init_localsbb, bblock);
5618                 
5619                 cfg->cbb = init_localsbb;
5620         } else {
5621                 start_bblock->next_bb = bblock;
5622                 link_bblock (cfg, start_bblock, bblock);
5623         }
5624
5625         /* at this point we know, if security is TRUE, that some code needs to be generated */
5626         if (security && (cfg->method == method)) {
5627                 MonoInst *args [2];
5628
5629                 mono_jit_stats.cas_demand_generation++;
5630
5631                 if (actions.demand.blob) {
5632                         /* Add code for SecurityAction.Demand */
5633                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5634                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
5635                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5636                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5637                 }
5638                 if (actions.noncasdemand.blob) {
5639                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5640                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5641                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5642                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5643                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5644                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5645                 }
5646                 if (actions.demandchoice.blob) {
5647                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5648                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5649                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5650                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5651                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
5652                 }
5653         }
5654
5655         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5656         if (pinvoke) {
5657                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
5658         }
5659
5660         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5661                 /* check if this is native code, e.g. an icall or a p/invoke */
5662                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5663                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5664                         if (wrapped) {
5665                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
5666                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
5667
5668                                 /* if this ia a native call then it can only be JITted from platform code */
5669                                 if ((icall || pinvk) && method->klass && method->klass->image) {
5670                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
5671                                                 MonoException *ex = icall ? mono_get_exception_security () : 
5672                                                         mono_get_exception_method_access ();
5673                                                 emit_throw_exception (cfg, ex);
5674                                         }
5675                                 }
5676                         }
5677                 }
5678         }
5679
5680         if (header->code_size == 0)
5681                 UNVERIFIED;
5682
5683         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
5684                 ip = err_pos;
5685                 UNVERIFIED;
5686         }
5687
5688         if (cfg->method == method)
5689                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5690
5691         for (n = 0; n < header->num_locals; ++n) {
5692                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5693                         UNVERIFIED;
5694         }
5695         class_inits = NULL;
5696
5697         /* We force the vtable variable here for all shared methods
5698            for the possibility that they might show up in a stack
5699            trace where their exact instantiation is needed. */
5700         if (cfg->generic_sharing_context && method == cfg->method) {
5701                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5702                                 mini_method_get_context (method)->method_inst ||
5703                                 method->klass->valuetype) {
5704                         mono_get_vtable_var (cfg);
5705                 } else {
5706                         /* FIXME: Is there a better way to do this?
5707                            We need the variable live for the duration
5708                            of the whole method. */
5709                         cfg->args [0]->flags |= MONO_INST_INDIRECT;
5710                 }
5711         }
5712
5713         /* add a check for this != NULL to inlined methods */
5714         if (is_virtual_call) {
5715                 MonoInst *arg_ins;
5716
5717                 NEW_ARGLOAD (cfg, arg_ins, 0);
5718                 MONO_ADD_INS (cfg->cbb, arg_ins);
5719                 cfg->flags |= MONO_CFG_HAS_CHECK_THIS;
5720                 MONO_EMIT_NEW_UNALU (cfg, OP_CHECK_THIS, -1, arg_ins->dreg);
5721                 MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, arg_ins->dreg);
5722         }
5723
5724         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5725         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5726
5727         ins_flag = 0;
5728         start_new_bblock = 0;
5729         cfg->cbb = bblock;
5730         while (ip < end) {
5731
5732                 if (cfg->method == method)
5733                         cfg->real_offset = ip - header->code;
5734                 else
5735                         cfg->real_offset = inline_offset;
5736                 cfg->ip = ip;
5737
5738                 context_used = 0;
5739                 
5740                 if (start_new_bblock) {
5741                         bblock->cil_length = ip - bblock->cil_code;
5742                         if (start_new_bblock == 2) {
5743                                 g_assert (ip == tblock->cil_code);
5744                         } else {
5745                                 GET_BBLOCK (cfg, tblock, ip);
5746                         }
5747                         bblock->next_bb = tblock;
5748                         bblock = tblock;
5749                         cfg->cbb = bblock;
5750                         start_new_bblock = 0;
5751                         for (i = 0; i < bblock->in_scount; ++i) {
5752                                 if (cfg->verbose_level > 3)
5753                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5754                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5755                                 *sp++ = ins;
5756                         }
5757                         if (class_inits)
5758                                 g_slist_free (class_inits);
5759                         class_inits = NULL;
5760                 } else {
5761                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5762                                 link_bblock (cfg, bblock, tblock);
5763                                 if (sp != stack_start) {
5764                                         handle_stack_args (cfg, stack_start, sp - stack_start);
5765                                         sp = stack_start;
5766                                         CHECK_UNVERIFIABLE (cfg);
5767                                 }
5768                                 bblock->next_bb = tblock;
5769                                 bblock = tblock;
5770                                 cfg->cbb = bblock;
5771                                 for (i = 0; i < bblock->in_scount; ++i) {
5772                                         if (cfg->verbose_level > 3)
5773                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5774                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5775                                         *sp++ = ins;
5776                                 }
5777                                 g_slist_free (class_inits);
5778                                 class_inits = NULL;
5779                         }
5780                 }
5781
5782                 bblock->real_offset = cfg->real_offset;
5783
5784                 if ((cfg->method == method) && cfg->coverage_info) {
5785                         guint32 cil_offset = ip - header->code;
5786                         cfg->coverage_info->data [cil_offset].cil_code = ip;
5787
5788                         /* TODO: Use an increment here */
5789 #if defined(TARGET_X86)
5790                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
5791                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
5792                         ins->inst_imm = 1;
5793                         MONO_ADD_INS (cfg->cbb, ins);
5794 #else
5795                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
5796                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
5797 #endif
5798                 }
5799
5800                 if (cfg->verbose_level > 3)
5801                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
5802
5803                 switch (*ip) {
5804                 case CEE_NOP:
5805                         if (cfg->keep_cil_nops)
5806                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
5807                         else
5808                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5809                         ip++;
5810                         MONO_ADD_INS (bblock, ins);
5811                         break;
5812                 case CEE_BREAK:
5813                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5814                         ip++;
5815                         MONO_ADD_INS (bblock, ins);
5816                         break;
5817                 case CEE_LDARG_0:
5818                 case CEE_LDARG_1:
5819                 case CEE_LDARG_2:
5820                 case CEE_LDARG_3:
5821                         CHECK_STACK_OVF (1);
5822                         n = (*ip)-CEE_LDARG_0;
5823                         CHECK_ARG (n);
5824                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5825                         ip++;
5826                         *sp++ = ins;
5827                         break;
5828                 case CEE_LDLOC_0:
5829                 case CEE_LDLOC_1:
5830                 case CEE_LDLOC_2:
5831                 case CEE_LDLOC_3:
5832                         CHECK_STACK_OVF (1);
5833                         n = (*ip)-CEE_LDLOC_0;
5834                         CHECK_LOCAL (n);
5835                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5836                         ip++;
5837                         *sp++ = ins;
5838                         break;
5839                 case CEE_STLOC_0:
5840                 case CEE_STLOC_1:
5841                 case CEE_STLOC_2:
5842                 case CEE_STLOC_3: {
5843                         CHECK_STACK (1);
5844                         n = (*ip)-CEE_STLOC_0;
5845                         CHECK_LOCAL (n);
5846                         --sp;
5847                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
5848                                 UNVERIFIED;
5849                         emit_stloc_ir (cfg, sp, header, n);
5850                         ++ip;
5851                         inline_costs += 1;
5852                         break;
5853                         }
5854                 case CEE_LDARG_S:
5855                         CHECK_OPSIZE (2);
5856                         CHECK_STACK_OVF (1);
5857                         n = ip [1];
5858                         CHECK_ARG (n);
5859                         EMIT_NEW_ARGLOAD (cfg, ins, n);
5860                         *sp++ = ins;
5861                         ip += 2;
5862                         break;
5863                 case CEE_LDARGA_S:
5864                         CHECK_OPSIZE (2);
5865                         CHECK_STACK_OVF (1);
5866                         n = ip [1];
5867                         CHECK_ARG (n);
5868                         NEW_ARGLOADA (cfg, ins, n);
5869                         MONO_ADD_INS (cfg->cbb, ins);
5870                         *sp++ = ins;
5871                         ip += 2;
5872                         break;
5873                 case CEE_STARG_S:
5874                         CHECK_OPSIZE (2);
5875                         CHECK_STACK (1);
5876                         --sp;
5877                         n = ip [1];
5878                         CHECK_ARG (n);
5879                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
5880                                 UNVERIFIED;
5881                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
5882                         ip += 2;
5883                         break;
5884                 case CEE_LDLOC_S:
5885                         CHECK_OPSIZE (2);
5886                         CHECK_STACK_OVF (1);
5887                         n = ip [1];
5888                         CHECK_LOCAL (n);
5889                         EMIT_NEW_LOCLOAD (cfg, ins, n);
5890                         *sp++ = ins;
5891                         ip += 2;
5892                         break;
5893                 case CEE_LDLOCA_S: {
5894                         unsigned char *tmp_ip;
5895                         CHECK_OPSIZE (2);
5896                         CHECK_STACK_OVF (1);
5897                         CHECK_LOCAL (ip [1]);
5898
5899                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
5900                                 ip = tmp_ip;
5901                                 inline_costs += 1;
5902                                 break;
5903                         }
5904
5905                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
5906                         *sp++ = ins;
5907                         ip += 2;
5908                         break;
5909                 }
5910                 case CEE_STLOC_S:
5911                         CHECK_OPSIZE (2);
5912                         CHECK_STACK (1);
5913                         --sp;
5914                         CHECK_LOCAL (ip [1]);
5915                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
5916                                 UNVERIFIED;
5917                         emit_stloc_ir (cfg, sp, header, ip [1]);
5918                         ip += 2;
5919                         inline_costs += 1;
5920                         break;
5921                 case CEE_LDNULL:
5922                         CHECK_STACK_OVF (1);
5923                         EMIT_NEW_PCONST (cfg, ins, NULL);
5924                         ins->type = STACK_OBJ;
5925                         ++ip;
5926                         *sp++ = ins;
5927                         break;
5928                 case CEE_LDC_I4_M1:
5929                         CHECK_STACK_OVF (1);
5930                         EMIT_NEW_ICONST (cfg, ins, -1);
5931                         ++ip;
5932                         *sp++ = ins;
5933                         break;
5934                 case CEE_LDC_I4_0:
5935                 case CEE_LDC_I4_1:
5936                 case CEE_LDC_I4_2:
5937                 case CEE_LDC_I4_3:
5938                 case CEE_LDC_I4_4:
5939                 case CEE_LDC_I4_5:
5940                 case CEE_LDC_I4_6:
5941                 case CEE_LDC_I4_7:
5942                 case CEE_LDC_I4_8:
5943                         CHECK_STACK_OVF (1);
5944                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
5945                         ++ip;
5946                         *sp++ = ins;
5947                         break;
5948                 case CEE_LDC_I4_S:
5949                         CHECK_OPSIZE (2);
5950                         CHECK_STACK_OVF (1);
5951                         ++ip;
5952                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
5953                         ++ip;
5954                         *sp++ = ins;
5955                         break;
5956                 case CEE_LDC_I4:
5957                         CHECK_OPSIZE (5);
5958                         CHECK_STACK_OVF (1);
5959                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
5960                         ip += 5;
5961                         *sp++ = ins;
5962                         break;
5963                 case CEE_LDC_I8:
5964                         CHECK_OPSIZE (9);
5965                         CHECK_STACK_OVF (1);
5966                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
5967                         ins->type = STACK_I8;
5968                         ins->dreg = alloc_dreg (cfg, STACK_I8);
5969                         ++ip;
5970                         ins->inst_l = (gint64)read64 (ip);
5971                         MONO_ADD_INS (bblock, ins);
5972                         ip += 8;
5973                         *sp++ = ins;
5974                         break;
5975                 case CEE_LDC_R4: {
5976                         float *f;
5977                         gboolean use_aotconst = FALSE;
5978
5979 #ifdef TARGET_POWERPC
5980                         /* FIXME: Clean this up */
5981                         if (cfg->compile_aot)
5982                                 use_aotconst = TRUE;
5983 #endif
5984
5985                         /* FIXME: we should really allocate this only late in the compilation process */
5986                         f = mono_domain_alloc (cfg->domain, sizeof (float));
5987                         CHECK_OPSIZE (5);
5988                         CHECK_STACK_OVF (1);
5989
5990                         if (use_aotconst) {
5991                                 MonoInst *cons;
5992                                 int dreg;
5993
5994                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
5995
5996                                 dreg = alloc_freg (cfg);
5997                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
5998                                 ins->type = STACK_R8;
5999                         } else {
6000                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6001                                 ins->type = STACK_R8;
6002                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
6003                                 ins->inst_p0 = f;
6004                                 MONO_ADD_INS (bblock, ins);
6005                         }
6006                         ++ip;
6007                         readr4 (ip, f);
6008                         ip += 4;
6009                         *sp++ = ins;                    
6010                         break;
6011                 }
6012                 case CEE_LDC_R8: {
6013                         double *d;
6014                         gboolean use_aotconst = FALSE;
6015
6016 #ifdef TARGET_POWERPC
6017                         /* FIXME: Clean this up */
6018                         if (cfg->compile_aot)
6019                                 use_aotconst = TRUE;
6020 #endif
6021
6022                         /* FIXME: we should really allocate this only late in the compilation process */
6023                         d = mono_domain_alloc (cfg->domain, sizeof (double));
6024                         CHECK_OPSIZE (9);
6025                         CHECK_STACK_OVF (1);
6026
6027                         if (use_aotconst) {
6028                                 MonoInst *cons;
6029                                 int dreg;
6030
6031                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
6032
6033                                 dreg = alloc_freg (cfg);
6034                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
6035                                 ins->type = STACK_R8;
6036                         } else {
6037                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6038                                 ins->type = STACK_R8;
6039                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
6040                                 ins->inst_p0 = d;
6041                                 MONO_ADD_INS (bblock, ins);
6042                         }
6043                         ++ip;
6044                         readr8 (ip, d);
6045                         ip += 8;
6046                         *sp++ = ins;
6047                         break;
6048                 }
6049                 case CEE_DUP: {
6050                         MonoInst *temp, *store;
6051                         CHECK_STACK (1);
6052                         CHECK_STACK_OVF (1);
6053                         sp--;
6054                         ins = *sp;
6055
6056                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6057                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6058
6059                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6060                         *sp++ = ins;
6061
6062                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6063                         *sp++ = ins;
6064
6065                         ++ip;
6066                         inline_costs += 2;
6067                         break;
6068                 }
6069                 case CEE_POP:
6070                         CHECK_STACK (1);
6071                         ip++;
6072                         --sp;
6073
6074 #ifdef TARGET_X86
6075                         if (sp [0]->type == STACK_R8)
6076                                 /* we need to pop the value from the x86 FP stack */
6077                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
6078 #endif
6079                         break;
6080                 case CEE_JMP: {
6081                         MonoCallInst *call;
6082
6083                         INLINE_FAILURE;
6084
6085                         CHECK_OPSIZE (5);
6086                         if (stack_start != sp)
6087                                 UNVERIFIED;
6088                         token = read32 (ip + 1);
6089                         /* FIXME: check the signature matches */
6090                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6091
6092                         if (!cmethod)
6093                                 goto load_error;
6094  
6095                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6096                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6097
6098                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
6099                                 CHECK_CFG_EXCEPTION;
6100
6101 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6102                         {
6103                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
6104                                 int i, n;
6105
6106                                 /* Handle tail calls similarly to calls */
6107                                 n = fsig->param_count + fsig->hasthis;
6108
6109                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
6110                                 call->method = cmethod;
6111                                 call->tail_call = TRUE;
6112                                 call->signature = mono_method_signature (cmethod);
6113                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
6114                                 call->inst.inst_p0 = cmethod;
6115                                 for (i = 0; i < n; ++i)
6116                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
6117
6118                                 mono_arch_emit_call (cfg, call);
6119                                 MONO_ADD_INS (bblock, (MonoInst*)call);
6120                         }
6121 #else
6122                         for (i = 0; i < num_args; ++i)
6123                                 /* Prevent arguments from being optimized away */
6124                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
6125
6126                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6127                         ins = (MonoInst*)call;
6128                         ins->inst_p0 = cmethod;
6129                         MONO_ADD_INS (bblock, ins);
6130 #endif
6131
6132                         ip += 5;
6133                         start_new_bblock = 1;
6134                         break;
6135                 }
6136                 case CEE_CALLI:
6137                 case CEE_CALL:
6138                 case CEE_CALLVIRT: {
6139                         MonoInst *addr = NULL;
6140                         MonoMethodSignature *fsig = NULL;
6141                         int array_rank = 0;
6142                         int virtual = *ip == CEE_CALLVIRT;
6143                         int calli = *ip == CEE_CALLI;
6144                         gboolean pass_imt_from_rgctx = FALSE;
6145                         MonoInst *imt_arg = NULL;
6146                         gboolean pass_vtable = FALSE;
6147                         gboolean pass_mrgctx = FALSE;
6148                         MonoInst *vtable_arg = NULL;
6149                         gboolean check_this = FALSE;
6150                         gboolean supported_tail_call = FALSE;
6151
6152                         CHECK_OPSIZE (5);
6153                         token = read32 (ip + 1);
6154
6155                         if (calli) {
6156                                 cmethod = NULL;
6157                                 CHECK_STACK (1);
6158                                 --sp;
6159                                 addr = *sp;
6160                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6161                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6162                                 else
6163                                         fsig = mono_metadata_parse_signature (image, token);
6164
6165                                 n = fsig->param_count + fsig->hasthis;
6166                         } else {
6167                                 MonoMethod *cil_method;
6168                                 
6169                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6170                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6171                                         cil_method = cmethod;
6172                                 } else if (constrained_call) {
6173                                         if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
6174                                                 /* 
6175                                                  * This is needed since get_method_constrained can't find 
6176                                                  * the method in klass representing a type var.
6177                                                  * The type var is guaranteed to be a reference type in this
6178                                                  * case.
6179                                                  */
6180                                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6181                                                 cil_method = cmethod;
6182                                                 g_assert (!cmethod->klass->valuetype);
6183                                         } else {
6184                                                 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6185                                         }
6186                                 } else {
6187                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6188                                         cil_method = cmethod;
6189                                 }
6190
6191                                 if (!cmethod)
6192                                         goto load_error;
6193                                 if (!dont_verify && !cfg->skip_visibility) {
6194                                         MonoMethod *target_method = cil_method;
6195                                         if (method->is_inflated) {
6196                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6197                                         }
6198                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6199                                                 !mono_method_can_access_method (method, cil_method))
6200                                                 METHOD_ACCESS_FAILURE;
6201                                 }
6202
6203                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6204                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6205
6206                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6207                                         /* MS.NET seems to silently convert this to a callvirt */
6208                                         virtual = 1;
6209
6210                                 if (!cmethod->klass->inited)
6211                                         if (!mono_class_init (cmethod->klass))
6212                                                 goto load_error;
6213
6214                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6215                                     mini_class_is_system_array (cmethod->klass)) {
6216                                         array_rank = cmethod->klass->rank;
6217                                         fsig = mono_method_signature (cmethod);
6218                                 } else {
6219                                         if (mono_method_signature (cmethod)->pinvoke) {
6220                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
6221                                                         check_for_pending_exc, FALSE);
6222                                                 fsig = mono_method_signature (wrapper);
6223                                         } else if (constrained_call) {
6224                                                 fsig = mono_method_signature (cmethod);
6225                                         } else {
6226                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6227                                         }
6228                                 }
6229
6230                                 mono_save_token_info (cfg, image, token, cil_method);
6231
6232                                 n = fsig->param_count + fsig->hasthis;
6233
6234                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6235                                         if (check_linkdemand (cfg, method, cmethod))
6236                                                 INLINE_FAILURE;
6237                                         CHECK_CFG_EXCEPTION;
6238                                 }
6239
6240                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
6241                                         g_assert_not_reached ();
6242                         }
6243
6244                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6245                                 UNVERIFIED;
6246
6247                         if (!cfg->generic_sharing_context && cmethod)
6248                                 g_assert (!mono_method_check_context_used (cmethod));
6249
6250                         CHECK_STACK (n);
6251
6252                         //g_assert (!virtual || fsig->hasthis);
6253
6254                         sp -= n;
6255
6256                         if (constrained_call) {
6257                                 /*
6258                                  * We have the `constrained.' prefix opcode.
6259                                  */
6260                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6261                                         int dreg;
6262
6263                                         /*
6264                                          * The type parameter is instantiated as a valuetype,
6265                                          * but that type doesn't override the method we're
6266                                          * calling, so we need to box `this'.
6267                                          */
6268                                         dreg = alloc_dreg (cfg, STACK_VTYPE);
6269                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADV_MEMBASE, dreg, sp [0]->dreg, 0);
6270                                         ins->klass = constrained_call;
6271                                         sp [0] = handle_box (cfg, ins, constrained_call);
6272                                         CHECK_CFG_EXCEPTION;
6273                                 } else if (!constrained_call->valuetype) {
6274                                         int dreg = alloc_preg (cfg);
6275
6276                                         /*
6277                                          * The type parameter is instantiated as a reference
6278                                          * type.  We have a managed pointer on the stack, so
6279                                          * we need to dereference it here.
6280                                          */
6281                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
6282                                         ins->type = STACK_OBJ;
6283                                         sp [0] = ins;
6284                                 } else if (cmethod->klass->valuetype)
6285                                         virtual = 0;
6286                                 constrained_call = NULL;
6287                         }
6288
6289                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6290                                 UNVERIFIED;
6291
6292                         /* 
6293                          * If the callee is a shared method, then its static cctor
6294                          * might not get called after the call was patched.
6295                          */
6296                         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)) {
6297                                 emit_generic_class_init (cfg, cmethod->klass);
6298                                 CHECK_TYPELOAD (cmethod->klass);
6299                         }
6300
6301                         if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
6302                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6303                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6304                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6305                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6306
6307                                 /*
6308                                  * Pass vtable iff target method might
6309                                  * be shared, which means that sharing
6310                                  * is enabled for its class and its
6311                                  * context is sharable (and it's not a
6312                                  * generic method).
6313                                  */
6314                                 if (sharing_enabled && context_sharable &&
6315                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6316                                         pass_vtable = TRUE;
6317                         }
6318
6319                         if (cmethod && mini_method_get_context (cmethod) &&
6320                                         mini_method_get_context (cmethod)->method_inst) {
6321                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6322                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6323                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6324
6325                                 g_assert (!pass_vtable);
6326
6327                                 if (sharing_enabled && context_sharable)
6328                                         pass_mrgctx = TRUE;
6329                         }
6330
6331                         if (cfg->generic_sharing_context && cmethod) {
6332                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6333
6334                                 context_used = mono_method_check_context_used (cmethod);
6335
6336                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6337                                         /* Generic method interface
6338                                            calls are resolved via a
6339                                            helper function and don't
6340                                            need an imt. */
6341                                         if (!cmethod_context || !cmethod_context->method_inst)
6342                                                 pass_imt_from_rgctx = TRUE;
6343                                 }
6344
6345                                 /*
6346                                  * If a shared method calls another
6347                                  * shared method then the caller must
6348                                  * have a generic sharing context
6349                                  * because the magic trampoline
6350                                  * requires it.  FIXME: We shouldn't
6351                                  * have to force the vtable/mrgctx
6352                                  * variable here.  Instead there
6353                                  * should be a flag in the cfg to
6354                                  * request a generic sharing context.
6355                                  */
6356                                 if (context_used &&
6357                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
6358                                         mono_get_vtable_var (cfg);
6359                         }
6360
6361                         if (pass_vtable) {
6362                                 if (context_used) {
6363                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
6364                                 } else {
6365                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6366
6367                                         CHECK_TYPELOAD (cmethod->klass);
6368                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
6369                                 }
6370                         }
6371
6372                         if (pass_mrgctx) {
6373                                 g_assert (!vtable_arg);
6374
6375                                 if (context_used) {
6376                                         vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
6377                                 } else {
6378                                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
6379                                 }
6380
6381                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6382                                                 MONO_METHOD_IS_FINAL (cmethod)) {
6383                                         if (virtual)
6384                                                 check_this = TRUE;
6385                                         virtual = 0;
6386                                 }
6387                         }
6388
6389                         if (pass_imt_from_rgctx) {
6390                                 g_assert (!pass_vtable);
6391                                 g_assert (cmethod);
6392
6393                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
6394                                         cmethod, MONO_RGCTX_INFO_METHOD);
6395                         }
6396
6397                         if (check_this) {
6398                                 MonoInst *check;
6399
6400                                 MONO_INST_NEW (cfg, check, OP_CHECK_THIS);
6401                                 check->sreg1 = sp [0]->dreg;
6402                                 MONO_ADD_INS (cfg->cbb, check);
6403                         }
6404
6405                         /* Calling virtual generic methods */
6406                         if (cmethod && virtual && 
6407                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6408                             !(MONO_METHOD_IS_FINAL (cmethod) && 
6409                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6410                             mono_method_signature (cmethod)->generic_param_count) {
6411                                 MonoInst *this_temp, *this_arg_temp, *store;
6412                                 MonoInst *iargs [4];
6413
6414                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6415
6416                                 /* Prevent inlining of methods that contain indirect calls */
6417                                 INLINE_FAILURE;
6418
6419 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && !defined(ENABLE_LLVM)
6420                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
6421                                         g_assert (!imt_arg);
6422                                         if (context_used) {
6423                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
6424                                                         cmethod, MONO_RGCTX_INFO_METHOD);
6425
6426                                         } else {
6427                                                 g_assert (cmethod->is_inflated);
6428                                                 EMIT_NEW_METHODCONST (cfg, imt_arg, cmethod);
6429                                         }
6430                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
6431                                 } else
6432 #endif
6433                                 {
6434                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6435                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6436                                         MONO_ADD_INS (bblock, store);
6437
6438                                         /* FIXME: This should be a managed pointer */
6439                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6440
6441                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6442                                         if (context_used) {
6443                                                 iargs [1] = emit_get_rgctx_method (cfg, context_used,
6444                                                         cmethod, MONO_RGCTX_INFO_METHOD);
6445                                                 EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6446                                                 addr = mono_emit_jit_icall (cfg,
6447                                                                 mono_helper_compile_generic_method, iargs);
6448                                         } else {
6449                                                 EMIT_NEW_METHODCONST (cfg, iargs [1], cmethod);
6450                                                 EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6451                                                 addr = mono_emit_jit_icall (cfg, mono_helper_compile_generic_method, iargs);
6452                                         }
6453
6454                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6455
6456                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6457                                 }
6458
6459                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6460                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6461
6462                                 ip += 5;
6463                                 ins_flag = 0;
6464                                 break;
6465                         }
6466
6467 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6468                         supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
6469 #else
6470                         supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6471 #endif
6472
6473                         /* Tail prefix */
6474                         /* FIXME: runtime generic context pointer for jumps? */
6475                         /* FIXME: handle this for generic sharing eventually */
6476                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
6477                                 MonoCallInst *call;
6478
6479                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6480                                 INLINE_FAILURE;
6481
6482 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6483                                 /* Handle tail calls similarly to calls */
6484                                 call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
6485 #else
6486                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6487                                 call->tail_call = TRUE;
6488                                 call->method = cmethod;
6489                                 call->signature = mono_method_signature (cmethod);
6490
6491                                 /*
6492                                  * We implement tail calls by storing the actual arguments into the 
6493                                  * argument variables, then emitting a CEE_JMP.
6494                                  */
6495                                 for (i = 0; i < n; ++i) {
6496                                         /* Prevent argument from being register allocated */
6497                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6498                                         EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6499                                 }
6500 #endif
6501
6502                                 ins = (MonoInst*)call;
6503                                 ins->inst_p0 = cmethod;
6504                                 ins->inst_p1 = arg_array [0];
6505                                 MONO_ADD_INS (bblock, ins);
6506                                 link_bblock (cfg, bblock, end_bblock);                  
6507                                 start_new_bblock = 1;
6508                                 /* skip CEE_RET as well */
6509                                 ip += 6;
6510                                 ins_flag = 0;
6511                                 break;
6512                         }
6513
6514                         /* Conversion to a JIT intrinsic */
6515                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
6516                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6517                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
6518                                         *sp = ins;
6519                                         sp++;
6520                                 }
6521
6522                                 ip += 5;
6523                                 ins_flag = 0;
6524                                 break;
6525                         }
6526
6527                         /* Inlining */
6528                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
6529                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
6530                             mono_method_check_inlining (cfg, cmethod) &&
6531                                  !g_list_find (dont_inline, cmethod)) {
6532                                 int costs;
6533                                 gboolean allways = FALSE;
6534
6535                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6536                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6537                                         /* Prevent inlining of methods that call wrappers */
6538                                         INLINE_FAILURE;
6539                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6540                                         allways = TRUE;
6541                                 }
6542
6543                                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, allways))) {
6544                                         ip += 5;
6545                                         cfg->real_offset += 5;
6546                                         bblock = cfg->cbb;
6547
6548                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6549                                                 /* *sp is already set by inline_method */
6550                                                 sp++;
6551
6552                                         inline_costs += costs;
6553                                         ins_flag = 0;
6554                                         break;
6555                                 }
6556                         }
6557                         
6558                         inline_costs += 10 * num_calls++;
6559
6560                         /* Tail recursion elimination */
6561                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
6562                                 gboolean has_vtargs = FALSE;
6563                                 int i;
6564
6565                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6566                                 INLINE_FAILURE;
6567
6568                                 /* keep it simple */
6569                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6570                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6571                                                 has_vtargs = TRUE;
6572                                 }
6573
6574                                 if (!has_vtargs) {
6575                                         for (i = 0; i < n; ++i)
6576                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6577                                         MONO_INST_NEW (cfg, ins, OP_BR);
6578                                         MONO_ADD_INS (bblock, ins);
6579                                         tblock = start_bblock->out_bb [0];
6580                                         link_bblock (cfg, bblock, tblock);
6581                                         ins->inst_target_bb = tblock;
6582                                         start_new_bblock = 1;
6583
6584                                         /* skip the CEE_RET, too */
6585                                         if (ip_in_bb (cfg, bblock, ip + 5))
6586                                                 ip += 6;
6587                                         else
6588                                                 ip += 5;
6589
6590                                         ins_flag = 0;
6591                                         break;
6592                                 }
6593                         }
6594
6595                         /* Generic sharing */
6596                         /* FIXME: only do this for generic methods if
6597                            they are not shared! */
6598                         if (context_used && !imt_arg && !array_rank &&
6599                                         (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
6600                                                 !mono_class_generic_sharing_enabled (cmethod->klass)) &&
6601                                         (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
6602                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
6603                                 INLINE_FAILURE;
6604
6605                                 g_assert (cfg->generic_sharing_context && cmethod);
6606                                 g_assert (!addr);
6607
6608                                 /*
6609                                  * We are compiling a call to a
6610                                  * generic method from shared code,
6611                                  * which means that we have to look up
6612                                  * the method in the rgctx and do an
6613                                  * indirect call.
6614                                  */
6615                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
6616                         }
6617
6618                         /* Indirect calls */
6619                         if (addr) {
6620                                 g_assert (!imt_arg);
6621
6622                                 if (*ip == CEE_CALL)
6623                                         g_assert (context_used);
6624                                 else if (*ip == CEE_CALLI)
6625                                         g_assert (!vtable_arg);
6626                                 else
6627                                         /* FIXME: what the hell is this??? */
6628                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6629                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6630
6631                                 /* Prevent inlining of methods with indirect calls */
6632                                 INLINE_FAILURE;
6633
6634                                 if (vtable_arg) {
6635 #ifdef MONO_ARCH_RGCTX_REG
6636                                         MonoCallInst *call;
6637                                         int rgctx_reg = mono_alloc_preg (cfg);
6638
6639                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
6640                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6641                                         call = (MonoCallInst*)ins;
6642                                         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
6643                                         cfg->uses_rgctx_reg = TRUE;
6644                                         call->rgctx_reg = TRUE;
6645 #else
6646                                         NOT_IMPLEMENTED;
6647 #endif
6648                                 } else {
6649                                         if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6650                                                 /* 
6651                                                  * Instead of emitting an indirect call, emit a direct call
6652                                                  * with the contents of the aotconst as the patch info.
6653                                                  */
6654                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
6655                                                 NULLIFY_INS (addr);
6656                                         } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6657                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
6658                                                 NULLIFY_INS (addr);
6659                                         } else {
6660                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6661                                         }
6662                                 }
6663                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6664                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6665
6666                                 ip += 5;
6667                                 ins_flag = 0;
6668                                 break;
6669                         }
6670                                         
6671                         /* Array methods */
6672                         if (array_rank) {
6673                                 MonoInst *addr;
6674
6675                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6676                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6677                                                 MonoInst *iargs [2];
6678
6679                                                 iargs [0] = sp [0];
6680                                                 iargs [1] = sp [fsig->param_count];
6681                                                 
6682                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
6683                                         }
6684                                         
6685                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
6686                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, sp [fsig->param_count]->dreg);
6687                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6688                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6689
6690                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
6691
6692                                         *sp++ = ins;
6693                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
6694                                         if (!cmethod->klass->element_class->valuetype && !readonly)
6695                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
6696                                         CHECK_TYPELOAD (cmethod->klass);
6697                                         
6698                                         readonly = FALSE;
6699                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6700                                         *sp++ = addr;
6701                                 } else {
6702                                         g_assert_not_reached ();
6703                                 }
6704
6705                                 ip += 5;
6706                                 ins_flag = 0;
6707                                 break;
6708                         }
6709
6710                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
6711                         if (ins) {
6712                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6713                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6714
6715                                 ip += 5;
6716                                 ins_flag = 0;
6717                                 break;
6718                         }
6719
6720                         /* Common call */
6721                         INLINE_FAILURE;
6722                         if (vtable_arg) {
6723                                 ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
6724                                         NULL, vtable_arg);
6725                         } else if (imt_arg) {
6726                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
6727                         } else {
6728                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
6729                         }
6730
6731                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6732                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6733
6734                         ip += 5;
6735                         ins_flag = 0;
6736                         break;
6737                 }
6738                 case CEE_RET:
6739                         if (cfg->method != method) {
6740                                 /* return from inlined method */
6741                                 /* 
6742                                  * If in_count == 0, that means the ret is unreachable due to
6743                                  * being preceeded by a throw. In that case, inline_method () will
6744                                  * handle setting the return value 
6745                                  * (test case: test_0_inline_throw ()).
6746                                  */
6747                                 if (return_var && cfg->cbb->in_count) {
6748                                         MonoInst *store;
6749                                         CHECK_STACK (1);
6750                                         --sp;
6751                                         //g_assert (returnvar != -1);
6752                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
6753                                         cfg->ret_var_set = TRUE;
6754                                 } 
6755                         } else {
6756                                 if (cfg->ret) {
6757                                         MonoType *ret_type = mono_method_signature (method)->ret;
6758
6759                                         g_assert (!return_var);
6760                                         CHECK_STACK (1);
6761                                         --sp;
6762                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
6763                                                 MonoInst *ret_addr;
6764
6765                                                 if (!cfg->vret_addr) {
6766                                                         MonoInst *ins;
6767
6768                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
6769                                                 } else {
6770                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
6771
6772                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
6773                                                         ins->klass = mono_class_from_mono_type (ret_type);
6774                                                 }
6775                                         } else {
6776 #ifdef MONO_ARCH_SOFT_FLOAT
6777                                                 if (!ret_type->byref && ret_type->type == MONO_TYPE_R4) {
6778                                                         MonoInst *iargs [1];
6779                                                         MonoInst *conv;
6780
6781                                                         iargs [0] = *sp;
6782                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
6783                                                         mono_arch_emit_setret (cfg, method, conv);
6784                                                 } else {
6785                                                         mono_arch_emit_setret (cfg, method, *sp);
6786                                                 }
6787 #else
6788                                                 mono_arch_emit_setret (cfg, method, *sp);
6789 #endif
6790                                         }
6791                                 }
6792                         }
6793                         if (sp != stack_start)
6794                                 UNVERIFIED;
6795                         MONO_INST_NEW (cfg, ins, OP_BR);
6796                         ip++;
6797                         ins->inst_target_bb = end_bblock;
6798                         MONO_ADD_INS (bblock, ins);
6799                         link_bblock (cfg, bblock, end_bblock);
6800                         start_new_bblock = 1;
6801                         break;
6802                 case CEE_BR_S:
6803                         CHECK_OPSIZE (2);
6804                         MONO_INST_NEW (cfg, ins, OP_BR);
6805                         ip++;
6806                         target = ip + 1 + (signed char)(*ip);
6807                         ++ip;
6808                         GET_BBLOCK (cfg, tblock, target);
6809                         link_bblock (cfg, bblock, tblock);
6810                         ins->inst_target_bb = tblock;
6811                         if (sp != stack_start) {
6812                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6813                                 sp = stack_start;
6814                                 CHECK_UNVERIFIABLE (cfg);
6815                         }
6816                         MONO_ADD_INS (bblock, ins);
6817                         start_new_bblock = 1;
6818                         inline_costs += BRANCH_COST;
6819                         break;
6820                 case CEE_BEQ_S:
6821                 case CEE_BGE_S:
6822                 case CEE_BGT_S:
6823                 case CEE_BLE_S:
6824                 case CEE_BLT_S:
6825                 case CEE_BNE_UN_S:
6826                 case CEE_BGE_UN_S:
6827                 case CEE_BGT_UN_S:
6828                 case CEE_BLE_UN_S:
6829                 case CEE_BLT_UN_S:
6830                         CHECK_OPSIZE (2);
6831                         CHECK_STACK (2);
6832                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
6833                         ip++;
6834                         target = ip + 1 + *(signed char*)ip;
6835                         ip++;
6836
6837                         ADD_BINCOND (NULL);
6838
6839                         sp = stack_start;
6840                         inline_costs += BRANCH_COST;
6841                         break;
6842                 case CEE_BR:
6843                         CHECK_OPSIZE (5);
6844                         MONO_INST_NEW (cfg, ins, OP_BR);
6845                         ip++;
6846
6847                         target = ip + 4 + (gint32)read32(ip);
6848                         ip += 4;
6849                         GET_BBLOCK (cfg, tblock, target);
6850                         link_bblock (cfg, bblock, tblock);
6851                         ins->inst_target_bb = tblock;
6852                         if (sp != stack_start) {
6853                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6854                                 sp = stack_start;
6855                                 CHECK_UNVERIFIABLE (cfg);
6856                         }
6857
6858                         MONO_ADD_INS (bblock, ins);
6859
6860                         start_new_bblock = 1;
6861                         inline_costs += BRANCH_COST;
6862                         break;
6863                 case CEE_BRFALSE_S:
6864                 case CEE_BRTRUE_S:
6865                 case CEE_BRFALSE:
6866                 case CEE_BRTRUE: {
6867                         MonoInst *cmp;
6868                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
6869                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
6870                         guint32 opsize = is_short ? 1 : 4;
6871
6872                         CHECK_OPSIZE (opsize);
6873                         CHECK_STACK (1);
6874                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
6875                                 UNVERIFIED;
6876                         ip ++;
6877                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
6878                         ip += opsize;
6879
6880                         sp--;
6881
6882                         GET_BBLOCK (cfg, tblock, target);
6883                         link_bblock (cfg, bblock, tblock);
6884                         GET_BBLOCK (cfg, tblock, ip);
6885                         link_bblock (cfg, bblock, tblock);
6886
6887                         if (sp != stack_start) {
6888                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6889                                 CHECK_UNVERIFIABLE (cfg);
6890                         }
6891
6892                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
6893                         cmp->sreg1 = sp [0]->dreg;
6894                         type_from_op (cmp, sp [0], NULL);
6895                         CHECK_TYPE (cmp);
6896
6897 #if SIZEOF_REGISTER == 4
6898                         if (cmp->opcode == OP_LCOMPARE_IMM) {
6899                                 /* Convert it to OP_LCOMPARE */
6900                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
6901                                 ins->type = STACK_I8;
6902                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
6903                                 ins->inst_l = 0;
6904                                 MONO_ADD_INS (bblock, ins);
6905                                 cmp->opcode = OP_LCOMPARE;
6906                                 cmp->sreg2 = ins->dreg;
6907                         }
6908 #endif
6909                         MONO_ADD_INS (bblock, cmp);
6910
6911                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
6912                         type_from_op (ins, sp [0], NULL);
6913                         MONO_ADD_INS (bblock, ins);
6914                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
6915                         GET_BBLOCK (cfg, tblock, target);
6916                         ins->inst_true_bb = tblock;
6917                         GET_BBLOCK (cfg, tblock, ip);
6918                         ins->inst_false_bb = tblock;
6919                         start_new_bblock = 2;
6920
6921                         sp = stack_start;
6922                         inline_costs += BRANCH_COST;
6923                         break;
6924                 }
6925                 case CEE_BEQ:
6926                 case CEE_BGE:
6927                 case CEE_BGT:
6928                 case CEE_BLE:
6929                 case CEE_BLT:
6930                 case CEE_BNE_UN:
6931                 case CEE_BGE_UN:
6932                 case CEE_BGT_UN:
6933                 case CEE_BLE_UN:
6934                 case CEE_BLT_UN:
6935                         CHECK_OPSIZE (5);
6936                         CHECK_STACK (2);
6937                         MONO_INST_NEW (cfg, ins, *ip);
6938                         ip++;
6939                         target = ip + 4 + (gint32)read32(ip);
6940                         ip += 4;
6941
6942                         ADD_BINCOND (NULL);
6943
6944                         sp = stack_start;
6945                         inline_costs += BRANCH_COST;
6946                         break;
6947                 case CEE_SWITCH: {
6948                         MonoInst *src1;
6949                         MonoBasicBlock **targets;
6950                         MonoBasicBlock *default_bblock;
6951                         MonoJumpInfoBBTable *table;
6952                         int offset_reg = alloc_preg (cfg);
6953                         int target_reg = alloc_preg (cfg);
6954                         int table_reg = alloc_preg (cfg);
6955                         int sum_reg = alloc_preg (cfg);
6956                         gboolean use_op_switch;
6957
6958                         CHECK_OPSIZE (5);
6959                         CHECK_STACK (1);
6960                         n = read32 (ip + 1);
6961                         --sp;
6962                         src1 = sp [0];
6963                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
6964                                 UNVERIFIED;
6965
6966                         ip += 5;
6967                         CHECK_OPSIZE (n * sizeof (guint32));
6968                         target = ip + n * sizeof (guint32);
6969
6970                         GET_BBLOCK (cfg, default_bblock, target);
6971
6972                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
6973                         for (i = 0; i < n; ++i) {
6974                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
6975                                 targets [i] = tblock;
6976                                 ip += 4;
6977                         }
6978
6979                         if (sp != stack_start) {
6980                                 /* 
6981                                  * Link the current bb with the targets as well, so handle_stack_args
6982                                  * will set their in_stack correctly.
6983                                  */
6984                                 link_bblock (cfg, bblock, default_bblock);
6985                                 for (i = 0; i < n; ++i)
6986                                         link_bblock (cfg, bblock, targets [i]);
6987
6988                                 handle_stack_args (cfg, stack_start, sp - stack_start);
6989                                 sp = stack_start;
6990                                 CHECK_UNVERIFIABLE (cfg);
6991                         }
6992
6993                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
6994                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
6995                         bblock = cfg->cbb;
6996
6997                         for (i = 0; i < n; ++i)
6998                                 link_bblock (cfg, bblock, targets [i]);
6999
7000                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
7001                         table->table = targets;
7002                         table->table_size = n;
7003
7004                         use_op_switch = FALSE;
7005 #ifdef TARGET_ARM
7006                         /* ARM implements SWITCH statements differently */
7007                         /* FIXME: Make it use the generic implementation */
7008                         if (!cfg->compile_aot)
7009                                 use_op_switch = TRUE;
7010 #endif
7011
7012                         if (COMPILE_LLVM (cfg))
7013                                 use_op_switch = TRUE;
7014
7015                         cfg->cbb->has_jump_table = 1;
7016
7017                         if (use_op_switch) {
7018                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
7019                                 ins->sreg1 = src1->dreg;
7020                                 ins->inst_p0 = table;
7021                                 ins->inst_many_bb = targets;
7022                                 ins->klass = GUINT_TO_POINTER (n);
7023                                 MONO_ADD_INS (cfg->cbb, ins);
7024                         } else {
7025                                 if (sizeof (gpointer) == 8)
7026                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
7027                                 else
7028                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
7029
7030 #if SIZEOF_REGISTER == 8
7031                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
7032                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
7033 #endif
7034
7035                                 if (cfg->compile_aot) {
7036                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
7037                                 } else {
7038                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
7039                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
7040                                         ins->inst_p0 = table;
7041                                         ins->dreg = table_reg;
7042                                         MONO_ADD_INS (cfg->cbb, ins);
7043                                 }
7044
7045                                 /* FIXME: Use load_memindex */
7046                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
7047                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
7048                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
7049                         }
7050                         start_new_bblock = 1;
7051                         inline_costs += (BRANCH_COST * 2);
7052                         break;
7053                 }
7054                 case CEE_LDIND_I1:
7055                 case CEE_LDIND_U1:
7056                 case CEE_LDIND_I2:
7057                 case CEE_LDIND_U2:
7058                 case CEE_LDIND_I4:
7059                 case CEE_LDIND_U4:
7060                 case CEE_LDIND_I8:
7061                 case CEE_LDIND_I:
7062                 case CEE_LDIND_R4:
7063                 case CEE_LDIND_R8:
7064                 case CEE_LDIND_REF:
7065                         CHECK_STACK (1);
7066                         --sp;
7067
7068                         switch (*ip) {
7069                         case CEE_LDIND_R4:
7070                         case CEE_LDIND_R8:
7071                                 dreg = alloc_freg (cfg);
7072                                 break;
7073                         case CEE_LDIND_I8:
7074                                 dreg = alloc_lreg (cfg);
7075                                 break;
7076                         default:
7077                                 dreg = alloc_preg (cfg);
7078                         }
7079
7080                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
7081                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
7082                         ins->flags |= ins_flag;
7083                         ins_flag = 0;
7084                         MONO_ADD_INS (bblock, ins);
7085                         *sp++ = ins;
7086                         ++ip;
7087                         break;
7088                 case CEE_STIND_REF:
7089                 case CEE_STIND_I1:
7090                 case CEE_STIND_I2:
7091                 case CEE_STIND_I4:
7092                 case CEE_STIND_I8:
7093                 case CEE_STIND_R4:
7094                 case CEE_STIND_R8:
7095                 case CEE_STIND_I:
7096                         CHECK_STACK (2);
7097                         sp -= 2;
7098
7099                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
7100                         ins->flags |= ins_flag;
7101                         ins_flag = 0;
7102                         MONO_ADD_INS (bblock, ins);
7103
7104 #if HAVE_WRITE_BARRIERS
7105                         if (*ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0))) {
7106                                 /* insert call to write barrier */
7107                                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
7108                                 mono_emit_method_call (cfg, write_barrier, sp, NULL);
7109                         }
7110 #endif
7111
7112                         inline_costs += 1;
7113                         ++ip;
7114                         break;
7115
7116                 case CEE_MUL:
7117                         CHECK_STACK (2);
7118
7119                         MONO_INST_NEW (cfg, ins, (*ip));
7120                         sp -= 2;
7121                         ins->sreg1 = sp [0]->dreg;
7122                         ins->sreg2 = sp [1]->dreg;
7123                         type_from_op (ins, sp [0], sp [1]);
7124                         CHECK_TYPE (ins);
7125                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7126
7127                         /* Use the immediate opcodes if possible */
7128                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
7129                                 int imm_opcode = mono_op_to_op_imm (ins->opcode);
7130                                 if (imm_opcode != -1) {
7131                                         ins->opcode = imm_opcode;
7132                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
7133                                         ins->sreg2 = -1;
7134
7135                                         sp [1]->opcode = OP_NOP;
7136                                 }
7137                         }
7138
7139                         MONO_ADD_INS ((cfg)->cbb, (ins));
7140
7141                         *sp++ = mono_decompose_opcode (cfg, ins);
7142                         ip++;
7143                         break;
7144                 case CEE_ADD:
7145                 case CEE_SUB:
7146                 case CEE_DIV:
7147                 case CEE_DIV_UN:
7148                 case CEE_REM:
7149                 case CEE_REM_UN:
7150                 case CEE_AND:
7151                 case CEE_OR:
7152                 case CEE_XOR:
7153                 case CEE_SHL:
7154                 case CEE_SHR:
7155                 case CEE_SHR_UN:
7156                         CHECK_STACK (2);
7157
7158                         MONO_INST_NEW (cfg, ins, (*ip));
7159                         sp -= 2;
7160                         ins->sreg1 = sp [0]->dreg;
7161                         ins->sreg2 = sp [1]->dreg;
7162                         type_from_op (ins, sp [0], sp [1]);
7163                         CHECK_TYPE (ins);
7164                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
7165                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7166
7167                         /* FIXME: Pass opcode to is_inst_imm */
7168
7169                         /* Use the immediate opcodes if possible */
7170                         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)) {
7171                                 int imm_opcode;
7172
7173                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
7174                                 if (imm_opcode != -1) {
7175                                         ins->opcode = imm_opcode;
7176                                         if (sp [1]->opcode == OP_I8CONST) {
7177 #if SIZEOF_REGISTER == 8
7178                                                 ins->inst_imm = sp [1]->inst_l;
7179 #else
7180                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
7181                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
7182 #endif
7183                                         }
7184                                         else
7185                                                 ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
7186                                         ins->sreg2 = -1;
7187
7188                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
7189                                         if (sp [1]->next == NULL)
7190                                                 sp [1]->opcode = OP_NOP;
7191                                 }
7192                         }
7193                         MONO_ADD_INS ((cfg)->cbb, (ins));
7194
7195                         *sp++ = mono_decompose_opcode (cfg, ins);
7196                         ip++;
7197                         break;
7198                 case CEE_NEG:
7199                 case CEE_NOT:
7200                 case CEE_CONV_I1:
7201                 case CEE_CONV_I2:
7202                 case CEE_CONV_I4:
7203                 case CEE_CONV_R4:
7204                 case CEE_CONV_R8:
7205                 case CEE_CONV_U4:
7206                 case CEE_CONV_I8:
7207                 case CEE_CONV_U8:
7208                 case CEE_CONV_OVF_I8:
7209                 case CEE_CONV_OVF_U8:
7210                 case CEE_CONV_R_UN:
7211                         CHECK_STACK (1);
7212
7213                         /* Special case this earlier so we have long constants in the IR */
7214                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
7215                                 int data = sp [-1]->inst_c0;
7216                                 sp [-1]->opcode = OP_I8CONST;
7217                                 sp [-1]->type = STACK_I8;
7218 #if SIZEOF_REGISTER == 8
7219                                 if ((*ip) == CEE_CONV_U8)
7220                                         sp [-1]->inst_c0 = (guint32)data;
7221                                 else
7222                                         sp [-1]->inst_c0 = data;
7223 #else
7224                                 sp [-1]->inst_ls_word = data;
7225                                 if ((*ip) == CEE_CONV_U8)
7226                                         sp [-1]->inst_ms_word = 0;
7227                                 else
7228                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
7229 #endif
7230                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
7231                         }
7232                         else {
7233                                 ADD_UNOP (*ip);
7234                         }
7235                         ip++;
7236                         break;
7237                 case CEE_CONV_OVF_I4:
7238                 case CEE_CONV_OVF_I1:
7239                 case CEE_CONV_OVF_I2:
7240                 case CEE_CONV_OVF_I:
7241                 case CEE_CONV_OVF_U:
7242                         CHECK_STACK (1);
7243
7244                         if (sp [-1]->type == STACK_R8) {
7245                                 ADD_UNOP (CEE_CONV_OVF_I8);
7246                                 ADD_UNOP (*ip);
7247                         } else {
7248                                 ADD_UNOP (*ip);
7249                         }
7250                         ip++;
7251                         break;
7252                 case CEE_CONV_OVF_U1:
7253                 case CEE_CONV_OVF_U2:
7254                 case CEE_CONV_OVF_U4:
7255                         CHECK_STACK (1);
7256
7257                         if (sp [-1]->type == STACK_R8) {
7258                                 ADD_UNOP (CEE_CONV_OVF_U8);
7259                                 ADD_UNOP (*ip);
7260                         } else {
7261                                 ADD_UNOP (*ip);
7262                         }
7263                         ip++;
7264                         break;
7265                 case CEE_CONV_OVF_I1_UN:
7266                 case CEE_CONV_OVF_I2_UN:
7267                 case CEE_CONV_OVF_I4_UN:
7268                 case CEE_CONV_OVF_I8_UN:
7269                 case CEE_CONV_OVF_U1_UN:
7270                 case CEE_CONV_OVF_U2_UN:
7271                 case CEE_CONV_OVF_U4_UN:
7272                 case CEE_CONV_OVF_U8_UN:
7273                 case CEE_CONV_OVF_I_UN:
7274                 case CEE_CONV_OVF_U_UN:
7275                 case CEE_CONV_U2:
7276                 case CEE_CONV_U1:
7277                 case CEE_CONV_I:
7278                 case CEE_CONV_U:
7279                         CHECK_STACK (1);
7280                         ADD_UNOP (*ip);
7281                         ip++;
7282                         break;
7283                 case CEE_ADD_OVF:
7284                 case CEE_ADD_OVF_UN:
7285                 case CEE_MUL_OVF:
7286                 case CEE_MUL_OVF_UN:
7287                 case CEE_SUB_OVF:
7288                 case CEE_SUB_OVF_UN:
7289                         CHECK_STACK (2);
7290                         ADD_BINOP (*ip);
7291                         ip++;
7292                         break;
7293                 case CEE_CPOBJ:
7294                         CHECK_OPSIZE (5);
7295                         CHECK_STACK (2);
7296                         token = read32 (ip + 1);
7297                         klass = mini_get_class (method, token, generic_context);
7298                         CHECK_TYPELOAD (klass);
7299                         sp -= 2;
7300                         if (generic_class_is_reference_type (cfg, klass)) {
7301                                 MonoInst *store, *load;
7302                                 int dreg = alloc_preg (cfg);
7303
7304                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
7305                                 load->flags |= ins_flag;
7306                                 MONO_ADD_INS (cfg->cbb, load);
7307
7308                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
7309                                 store->flags |= ins_flag;
7310                                 MONO_ADD_INS (cfg->cbb, store);
7311                         } else {
7312                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7313                         }
7314                         ins_flag = 0;
7315                         ip += 5;
7316                         break;
7317                 case CEE_LDOBJ: {
7318                         int loc_index = -1;
7319                         int stloc_len = 0;
7320
7321                         CHECK_OPSIZE (5);
7322                         CHECK_STACK (1);
7323                         --sp;
7324                         token = read32 (ip + 1);
7325                         klass = mini_get_class (method, token, generic_context);
7326                         CHECK_TYPELOAD (klass);
7327
7328                         /* Optimize the common ldobj+stloc combination */
7329                         switch (ip [5]) {
7330                         case CEE_STLOC_S:
7331                                 loc_index = ip [6];
7332                                 stloc_len = 2;
7333                                 break;
7334                         case CEE_STLOC_0:
7335                         case CEE_STLOC_1:
7336                         case CEE_STLOC_2:
7337                         case CEE_STLOC_3:
7338                                 loc_index = ip [5] - CEE_STLOC_0;
7339                                 stloc_len = 1;
7340                                 break;
7341                         default:
7342                                 break;
7343                         }
7344
7345                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7346                                 CHECK_LOCAL (loc_index);
7347
7348                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7349                                 ins->dreg = cfg->locals [loc_index]->dreg;
7350                                 ip += 5;
7351                                 ip += stloc_len;
7352                                 break;
7353                         }
7354
7355                         /* Optimize the ldobj+stobj combination */
7356                         /* The reference case ends up being a load+store anyway */
7357                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
7358                                 CHECK_STACK (1);
7359
7360                                 sp --;
7361
7362                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7363
7364                                 ip += 5 + 5;
7365                                 ins_flag = 0;
7366                                 break;
7367                         }
7368
7369                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7370                         *sp++ = ins;
7371
7372                         ip += 5;
7373                         ins_flag = 0;
7374                         inline_costs += 1;
7375                         break;
7376                 }
7377                 case CEE_LDSTR:
7378                         CHECK_STACK_OVF (1);
7379                         CHECK_OPSIZE (5);
7380                         n = read32 (ip + 1);
7381
7382                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7383                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7384                                 ins->type = STACK_OBJ;
7385                                 *sp = ins;
7386                         }
7387                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7388                                 MonoInst *iargs [1];
7389
7390                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
7391                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
7392                         } else {
7393                                 if (cfg->opt & MONO_OPT_SHARED) {
7394                                         MonoInst *iargs [3];
7395
7396                                         if (cfg->compile_aot) {
7397                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7398                                         }
7399                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7400                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
7401                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7402                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
7403                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7404                                 } else {
7405                                         if (bblock->out_of_line) {
7406                                                 MonoInst *iargs [2];
7407
7408                                                 if (image == mono_defaults.corlib) {
7409                                                         /* 
7410                                                          * Avoid relocations in AOT and save some space by using a 
7411                                                          * version of helper_ldstr specialized to mscorlib.
7412                                                          */
7413                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7414                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
7415                                                 } else {
7416                                                         /* Avoid creating the string object */
7417                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
7418                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7419                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
7420                                                 }
7421                                         } 
7422                                         else
7423                                         if (cfg->compile_aot) {
7424                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7425                                                 *sp = ins;
7426                                                 MONO_ADD_INS (bblock, ins);
7427                                         } 
7428                                         else {
7429                                                 NEW_PCONST (cfg, ins, NULL);
7430                                                 ins->type = STACK_OBJ;
7431                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7432                                                 *sp = ins;
7433                                                 MONO_ADD_INS (bblock, ins);
7434                                         }
7435                                 }
7436                         }
7437
7438                         sp++;
7439                         ip += 5;
7440                         break;
7441                 case CEE_NEWOBJ: {
7442                         MonoInst *iargs [2];
7443                         MonoMethodSignature *fsig;
7444                         MonoInst this_ins;
7445                         MonoInst *alloc;
7446                         MonoInst *vtable_arg = NULL;
7447
7448                         CHECK_OPSIZE (5);
7449                         token = read32 (ip + 1);
7450                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7451                         if (!cmethod)
7452                                 goto load_error;
7453                         fsig = mono_method_get_signature (cmethod, image, token);
7454
7455                         mono_save_token_info (cfg, image, token, cmethod);
7456
7457                         if (!mono_class_init (cmethod->klass))
7458                                 goto load_error;
7459
7460                         if (cfg->generic_sharing_context)
7461                                 context_used = mono_method_check_context_used (cmethod);
7462
7463                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7464                                 if (check_linkdemand (cfg, method, cmethod))
7465                                         INLINE_FAILURE;
7466                                 CHECK_CFG_EXCEPTION;
7467                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7468                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7469                         }
7470
7471                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7472                                         mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
7473                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7474                                         if (context_used) {
7475                                                 vtable_arg = emit_get_rgctx_method (cfg, context_used,
7476                                                         cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7477                                         } else {
7478                                                 EMIT_NEW_METHOD_RGCTX_CONST (cfg, vtable_arg, cmethod);
7479                                         }
7480                                 } else {
7481                                         if (context_used) {
7482                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7483                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7484                                         } else {
7485                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7486
7487                                                 CHECK_TYPELOAD (cmethod->klass);
7488                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7489                                         }
7490                                 }
7491                         }
7492
7493                         n = fsig->param_count;
7494                         CHECK_STACK (n);
7495
7496                         /* 
7497                          * Generate smaller code for the common newobj <exception> instruction in
7498                          * argument checking code.
7499                          */
7500                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
7501                                 is_exception_class (cmethod->klass) && n <= 2 &&
7502                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7503                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7504                                 MonoInst *iargs [3];
7505
7506                                 g_assert (!vtable_arg);
7507
7508                                 sp -= n;
7509
7510                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7511                                 switch (n) {
7512                                 case 0:
7513                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
7514                                         break;
7515                                 case 1:
7516                                         iargs [1] = sp [0];
7517                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
7518                                         break;
7519                                 case 2:
7520                                         iargs [1] = sp [0];
7521                                         iargs [2] = sp [1];
7522                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
7523                                         break;
7524                                 default:
7525                                         g_assert_not_reached ();
7526                                 }
7527
7528                                 ip += 5;
7529                                 inline_costs += 5;
7530                                 break;
7531                         }
7532
7533                         /* move the args to allow room for 'this' in the first position */
7534                         while (n--) {
7535                                 --sp;
7536                                 sp [1] = sp [0];
7537                         }
7538
7539                         /* check_call_signature () requires sp[0] to be set */
7540                         this_ins.type = STACK_OBJ;
7541                         sp [0] = &this_ins;
7542                         if (check_call_signature (cfg, fsig, sp))
7543                                 UNVERIFIED;
7544
7545                         iargs [0] = NULL;
7546
7547                         if (mini_class_is_system_array (cmethod->klass)) {
7548                                 g_assert (!vtable_arg);
7549
7550                                 if (context_used) {
7551                                         *sp = emit_get_rgctx_method (cfg, context_used,
7552                                                 cmethod, MONO_RGCTX_INFO_METHOD);
7553                                 } else {
7554                                         EMIT_NEW_METHODCONST (cfg, *sp, cmethod);
7555                                 }
7556
7557                                 /* Avoid varargs in the common case */
7558                                 if (fsig->param_count == 1)
7559                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
7560                                 else if (fsig->param_count == 2)
7561                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
7562                                 else
7563                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
7564                         } else if (cmethod->string_ctor) {
7565                                 g_assert (!context_used);
7566                                 g_assert (!vtable_arg);
7567                                 /* we simply pass a null pointer */
7568                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
7569                                 /* now call the string ctor */
7570                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL);
7571                         } else {
7572                                 MonoInst* callvirt_this_arg = NULL;
7573                                 
7574                                 if (cmethod->klass->valuetype) {
7575                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7576                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
7577                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
7578
7579                                         alloc = NULL;
7580
7581                                         /* 
7582                                          * The code generated by mini_emit_virtual_call () expects
7583                                          * iargs [0] to be a boxed instance, but luckily the vcall
7584                                          * will be transformed into a normal call there.
7585                                          */
7586                                 } else if (context_used) {
7587                                         MonoInst *data;
7588                                         int rgctx_info;
7589
7590                                         if (cfg->opt & MONO_OPT_SHARED)
7591                                                 rgctx_info = MONO_RGCTX_INFO_KLASS;
7592                                         else
7593                                                 rgctx_info = MONO_RGCTX_INFO_VTABLE;
7594                                         data = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, rgctx_info);
7595
7596                                         alloc = handle_alloc_from_inst (cfg, cmethod->klass, data, FALSE);
7597                                         *sp = alloc;
7598                                 } else {
7599                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7600
7601                                         CHECK_TYPELOAD (cmethod->klass);
7602
7603                                         /*
7604                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
7605                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
7606                                          * As a workaround, we call class cctors before allocating objects.
7607                                          */
7608                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7609                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
7610                                                 if (cfg->verbose_level > 2)
7611                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7612                                                 class_inits = g_slist_prepend (class_inits, vtable);
7613                                         }
7614
7615                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE);
7616                                         *sp = alloc;
7617                                 }
7618                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
7619
7620                                 if (alloc)
7621                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
7622
7623                                 /* Now call the actual ctor */
7624                                 /* Avoid virtual calls to ctors if possible */
7625                                 if (cmethod->klass->marshalbyref)
7626                                         callvirt_this_arg = sp [0];
7627
7628                                 if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7629                                     mono_method_check_inlining (cfg, cmethod) &&
7630                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7631                                     !g_list_find (dont_inline, cmethod)) {
7632                                         int costs;
7633
7634                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
7635                                                 cfg->real_offset += 5;
7636                                                 bblock = cfg->cbb;
7637
7638                                                 inline_costs += costs - 5;
7639                                         } else {
7640                                                 INLINE_FAILURE;
7641                                                 mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
7642                                         }
7643                                 } else if (context_used &&
7644                                                 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
7645                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
7646                                         MonoInst *cmethod_addr;
7647
7648                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7649                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7650
7651                                         mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
7652                                 } else {
7653                                         INLINE_FAILURE;
7654                                         ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
7655                                                                                                                         callvirt_this_arg, NULL, vtable_arg);
7656                                 }
7657                         }
7658
7659                         if (alloc == NULL) {
7660                                 /* Valuetype */
7661                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
7662                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
7663                                 *sp++= ins;
7664                         }
7665                         else
7666                                 *sp++ = alloc;
7667                         
7668                         ip += 5;
7669                         inline_costs += 5;
7670                         break;
7671                 }
7672                 case CEE_CASTCLASS:
7673                         CHECK_STACK (1);
7674                         --sp;
7675                         CHECK_OPSIZE (5);
7676                         token = read32 (ip + 1);
7677                         klass = mini_get_class (method, token, generic_context);
7678                         CHECK_TYPELOAD (klass);
7679                         if (sp [0]->type != STACK_OBJ)
7680                                 UNVERIFIED;
7681
7682                         if (cfg->generic_sharing_context)
7683                                 context_used = mono_class_check_context_used (klass);
7684
7685                         if (context_used) {
7686                                 MonoInst *args [2];
7687
7688                                 /* obj */
7689                                 args [0] = *sp;
7690
7691                                 /* klass */
7692                                 args [1] = emit_get_rgctx_klass (cfg, context_used,
7693                                         klass, MONO_RGCTX_INFO_KLASS);
7694
7695                                 ins = mono_emit_jit_icall (cfg, mono_object_castclass, args);
7696                                 *sp ++ = ins;
7697                                 ip += 5;
7698                                 inline_costs += 2;
7699                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
7700                                 MonoMethod *mono_castclass;
7701                                 MonoInst *iargs [1];
7702                                 int costs;
7703
7704                                 mono_castclass = mono_marshal_get_castclass (klass); 
7705                                 iargs [0] = sp [0];
7706                                 
7707                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7708                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7709                                 g_assert (costs > 0);
7710                                 
7711                                 ip += 5;
7712                                 cfg->real_offset += 5;
7713                                 bblock = cfg->cbb;
7714
7715                                 *sp++ = iargs [0];
7716
7717                                 inline_costs += costs;
7718                         }
7719                         else {
7720                                 ins = handle_castclass (cfg, klass, *sp);
7721                                 CHECK_CFG_EXCEPTION;
7722                                 bblock = cfg->cbb;
7723                                 *sp ++ = ins;
7724                                 ip += 5;
7725                         }
7726                         break;
7727                 case CEE_ISINST: {
7728                         CHECK_STACK (1);
7729                         --sp;
7730                         CHECK_OPSIZE (5);
7731                         token = read32 (ip + 1);
7732                         klass = mini_get_class (method, token, generic_context);
7733                         CHECK_TYPELOAD (klass);
7734                         if (sp [0]->type != STACK_OBJ)
7735                                 UNVERIFIED;
7736  
7737                         if (cfg->generic_sharing_context)
7738                                 context_used = mono_class_check_context_used (klass);
7739
7740                         if (context_used) {
7741                                 MonoInst *args [2];
7742
7743                                 /* obj */
7744                                 args [0] = *sp;
7745
7746                                 /* klass */
7747                                 args [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
7748
7749                                 *sp = mono_emit_jit_icall (cfg, mono_object_isinst, args);
7750                                 sp++;
7751                                 ip += 5;
7752                                 inline_costs += 2;
7753                         } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                    
7754                                 MonoMethod *mono_isinst;
7755                                 MonoInst *iargs [1];
7756                                 int costs;
7757
7758                                 mono_isinst = mono_marshal_get_isinst (klass); 
7759                                 iargs [0] = sp [0];
7760
7761                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
7762                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);                     
7763                                 g_assert (costs > 0);
7764                                 
7765                                 ip += 5;
7766                                 cfg->real_offset += 5;
7767                                 bblock = cfg->cbb;
7768
7769                                 *sp++= iargs [0];
7770
7771                                 inline_costs += costs;
7772                         }
7773                         else {
7774                                 ins = handle_isinst (cfg, klass, *sp);
7775                                 CHECK_CFG_EXCEPTION;
7776                                 bblock = cfg->cbb;
7777                                 *sp ++ = ins;
7778                                 ip += 5;
7779                         }
7780                         break;
7781                 }
7782                 case CEE_UNBOX_ANY: {
7783                         CHECK_STACK (1);
7784                         --sp;
7785                         CHECK_OPSIZE (5);
7786                         token = read32 (ip + 1);
7787                         klass = mini_get_class (method, token, generic_context);
7788                         CHECK_TYPELOAD (klass);
7789  
7790                         mono_save_token_info (cfg, image, token, klass);
7791
7792                         if (cfg->generic_sharing_context)
7793                                 context_used = mono_class_check_context_used (klass);
7794
7795                         if (generic_class_is_reference_type (cfg, klass)) {
7796                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
7797                                 if (context_used) {
7798                                         MonoInst *iargs [2];
7799
7800                                         /* obj */
7801                                         iargs [0] = *sp;
7802                                         /* klass */
7803                                         iargs [1] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
7804                                         ins = mono_emit_jit_icall (cfg, mono_object_castclass, iargs);
7805                                         *sp ++ = ins;
7806                                         ip += 5;
7807                                         inline_costs += 2;
7808                                 } else if (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE) {                            
7809                                         MonoMethod *mono_castclass;
7810                                         MonoInst *iargs [1];
7811                                         int costs;
7812
7813                                         mono_castclass = mono_marshal_get_castclass (klass); 
7814                                         iargs [0] = sp [0];
7815
7816                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
7817                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
7818                         
7819                                         g_assert (costs > 0);
7820                                 
7821                                         ip += 5;
7822                                         cfg->real_offset += 5;
7823                                         bblock = cfg->cbb;
7824
7825                                         *sp++ = iargs [0];
7826                                         inline_costs += costs;
7827                                 } else {
7828                                         ins = handle_castclass (cfg, klass, *sp);
7829                                         CHECK_CFG_EXCEPTION;
7830                                         bblock = cfg->cbb;
7831                                         *sp ++ = ins;
7832                                         ip += 5;
7833                                 }
7834                                 break;
7835                         }
7836
7837                         if (mono_class_is_nullable (klass)) {
7838                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
7839                                 *sp++= ins;
7840                                 ip += 5;
7841                                 break;
7842                         }
7843
7844                         /* UNBOX */
7845                         ins = handle_unbox (cfg, klass, sp, context_used);
7846                         *sp = ins;
7847
7848                         ip += 5;
7849
7850                         /* LDOBJ */
7851                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7852                         *sp++ = ins;
7853
7854                         inline_costs += 2;
7855                         break;
7856                 }
7857                 case CEE_BOX: {
7858                         MonoInst *val;
7859
7860                         CHECK_STACK (1);
7861                         --sp;
7862                         val = *sp;
7863                         CHECK_OPSIZE (5);
7864                         token = read32 (ip + 1);
7865                         klass = mini_get_class (method, token, generic_context);
7866                         CHECK_TYPELOAD (klass);
7867
7868                         mono_save_token_info (cfg, image, token, klass);
7869
7870                         if (cfg->generic_sharing_context)
7871                                 context_used = mono_class_check_context_used (klass);
7872
7873                         if (generic_class_is_reference_type (cfg, klass)) {
7874                                 *sp++ = val;
7875                                 ip += 5;
7876                                 break;
7877                         }
7878
7879                         if (klass == mono_defaults.void_class)
7880                                 UNVERIFIED;
7881                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
7882                                 UNVERIFIED;
7883                         /* frequent check in generic code: box (struct), brtrue */
7884                         if (!mono_class_is_nullable (klass) &&
7885                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) && (ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S)) {
7886                                 /*printf ("box-brtrue opt at 0x%04x in %s\n", real_offset, method->name);*/
7887                                 ip += 5;
7888                                 MONO_INST_NEW (cfg, ins, OP_BR);
7889                                 if (*ip == CEE_BRTRUE_S) {
7890                                         CHECK_OPSIZE (2);
7891                                         ip++;
7892                                         target = ip + 1 + (signed char)(*ip);
7893                                         ip++;
7894                                 } else {
7895                                         CHECK_OPSIZE (5);
7896                                         ip++;
7897                                         target = ip + 4 + (gint)(read32 (ip));
7898                                         ip += 4;
7899                                 }
7900                                 GET_BBLOCK (cfg, tblock, target);
7901                                 link_bblock (cfg, bblock, tblock);
7902                                 ins->inst_target_bb = tblock;
7903                                 GET_BBLOCK (cfg, tblock, ip);
7904                                 /* 
7905                                  * This leads to some inconsistency, since the two bblocks are 
7906                                  * not really connected, but it is needed for handling stack 
7907                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
7908                                  * FIXME: This should only be needed if sp != stack_start, but that
7909                                  * doesn't work for some reason (test failure in mcs/tests on x86).
7910                                  */
7911                                 link_bblock (cfg, bblock, tblock);
7912                                 if (sp != stack_start) {
7913                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7914                                         sp = stack_start;
7915                                         CHECK_UNVERIFIABLE (cfg);
7916                                 }
7917                                 MONO_ADD_INS (bblock, ins);
7918                                 start_new_bblock = 1;
7919                                 break;
7920                         }
7921
7922                         if (context_used) {
7923                                 MonoInst *data;
7924                                 int rgctx_info;
7925
7926                                 if (cfg->opt & MONO_OPT_SHARED)
7927                                         rgctx_info = MONO_RGCTX_INFO_KLASS;
7928                                 else
7929                                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
7930                                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
7931                                 *sp++ = handle_box_from_inst (cfg, val, klass, context_used, data);
7932                         } else {
7933                                 *sp++ = handle_box (cfg, val, klass);
7934                         }
7935
7936                         CHECK_CFG_EXCEPTION;
7937                         ip += 5;
7938                         inline_costs += 1;
7939                         break;
7940                 }
7941                 case CEE_UNBOX: {
7942                         CHECK_STACK (1);
7943                         --sp;
7944                         CHECK_OPSIZE (5);
7945                         token = read32 (ip + 1);
7946                         klass = mini_get_class (method, token, generic_context);
7947                         CHECK_TYPELOAD (klass);
7948
7949                         mono_save_token_info (cfg, image, token, klass);
7950
7951                         if (cfg->generic_sharing_context)
7952                                 context_used = mono_class_check_context_used (klass);
7953
7954                         if (mono_class_is_nullable (klass)) {
7955                                 MonoInst *val;
7956
7957                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
7958                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
7959
7960                                 *sp++= ins;
7961                         } else {
7962                                 ins = handle_unbox (cfg, klass, sp, context_used);
7963                                 *sp++ = ins;
7964                         }
7965                         ip += 5;
7966                         inline_costs += 2;
7967                         break;
7968                 }
7969                 case CEE_LDFLD:
7970                 case CEE_LDFLDA:
7971                 case CEE_STFLD: {
7972                         MonoClassField *field;
7973                         int costs;
7974                         guint foffset;
7975
7976                         if (*ip == CEE_STFLD) {
7977                                 CHECK_STACK (2);
7978                                 sp -= 2;
7979                         } else {
7980                                 CHECK_STACK (1);
7981                                 --sp;
7982                         }
7983                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
7984                                 UNVERIFIED;
7985                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
7986                                 UNVERIFIED;
7987                         CHECK_OPSIZE (5);
7988                         token = read32 (ip + 1);
7989                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7990                                 field = mono_method_get_wrapper_data (method, token);
7991                                 klass = field->parent;
7992                         }
7993                         else {
7994                                 field = mono_field_from_token (image, token, &klass, generic_context);
7995                         }
7996                         if (!field)
7997                                 goto load_error;
7998                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
7999                                 FIELD_ACCESS_FAILURE;
8000                         mono_class_init (klass);
8001
8002                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
8003                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
8004                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8005                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8006                         */
8007
8008                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
8009                         if (*ip == CEE_STFLD) {
8010                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
8011                                         UNVERIFIED;
8012                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8013                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
8014                                         MonoInst *iargs [5];
8015
8016                                         iargs [0] = sp [0];
8017                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8018                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8019                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
8020                                                     field->offset);
8021                                         iargs [4] = sp [1];
8022
8023                                         if (cfg->opt & MONO_OPT_INLINE) {
8024                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
8025                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
8026                                                 g_assert (costs > 0);
8027                                                       
8028                                                 cfg->real_offset += 5;
8029                                                 bblock = cfg->cbb;
8030
8031                                                 inline_costs += costs;
8032                                         } else {
8033                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
8034                                         }
8035                                 } else {
8036                                         MonoInst *store;
8037
8038                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
8039
8040 #if HAVE_WRITE_BARRIERS
8041                                 if (mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
8042                                         /* insert call to write barrier */
8043                                         MonoMethod *write_barrier = mono_gc_get_write_barrier ();
8044                                         MonoInst *iargs [2];
8045                                         int dreg;
8046
8047                                         dreg = alloc_preg (cfg);
8048                                         EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8049                                         iargs [1] = sp [1];
8050                                         mono_emit_method_call (cfg, write_barrier, iargs, NULL);
8051                                 }
8052 #endif
8053
8054                                         store->flags |= ins_flag;
8055                                 }
8056                                 ins_flag = 0;
8057                                 ip += 5;
8058                                 break;
8059                         }
8060
8061                         if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8062                                 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
8063                                 MonoInst *iargs [4];
8064
8065                                 iargs [0] = sp [0];
8066                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8067                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8068                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
8069                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8070                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
8071                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8072                                         bblock = cfg->cbb;
8073                                         g_assert (costs > 0);
8074                                                       
8075                                         cfg->real_offset += 5;
8076
8077                                         *sp++ = iargs [0];
8078
8079                                         inline_costs += costs;
8080                                 } else {
8081                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
8082                                         *sp++ = ins;
8083                                 }
8084                         } else {
8085                                 if (sp [0]->type == STACK_VTYPE) {
8086                                         MonoInst *var;
8087
8088                                         /* Have to compute the address of the variable */
8089
8090                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
8091                                         if (!var)
8092                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
8093                                         else
8094                                                 g_assert (var->klass == klass);
8095                                         
8096                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
8097                                         sp [0] = ins;
8098                                 }
8099
8100                                 if (*ip == CEE_LDFLDA) {
8101                                         dreg = alloc_preg (cfg);
8102
8103                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8104                                         ins->klass = mono_class_from_mono_type (field->type);
8105                                         ins->type = STACK_MP;
8106                                         *sp++ = ins;
8107                                 } else {
8108                                         MonoInst *load;
8109
8110                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
8111                                         load->flags |= ins_flag;
8112                                         *sp++ = load;
8113                                 }
8114                         }
8115                         ins_flag = 0;
8116                         ip += 5;
8117                         break;
8118                 }
8119                 case CEE_LDSFLD:
8120                 case CEE_LDSFLDA:
8121                 case CEE_STSFLD: {
8122                         MonoClassField *field;
8123                         gpointer addr = NULL;
8124                         gboolean is_special_static;
8125
8126                         CHECK_OPSIZE (5);
8127                         token = read32 (ip + 1);
8128
8129                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8130                                 field = mono_method_get_wrapper_data (method, token);
8131                                 klass = field->parent;
8132                         }
8133                         else
8134                                 field = mono_field_from_token (image, token, &klass, generic_context);
8135                         if (!field)
8136                                 goto load_error;
8137                         mono_class_init (klass);
8138                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8139                                 FIELD_ACCESS_FAILURE;
8140
8141                         /* if the class is Critical then transparent code cannot access it's fields */
8142                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8143                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8144
8145                         /*
8146                          * We can only support shared generic static
8147                          * field access on architectures where the
8148                          * trampoline code has been extended to handle
8149                          * the generic class init.
8150                          */
8151 #ifndef MONO_ARCH_VTABLE_REG
8152                         GENERIC_SHARING_FAILURE (*ip);
8153 #endif
8154
8155                         if (cfg->generic_sharing_context)
8156                                 context_used = mono_class_check_context_used (klass);
8157
8158                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
8159
8160                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
8161                          * to be called here.
8162                          */
8163                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
8164                                 mono_class_vtable (cfg->domain, klass);
8165                                 CHECK_TYPELOAD (klass);
8166                         }
8167                         mono_domain_lock (cfg->domain);
8168                         if (cfg->domain->special_static_fields)
8169                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8170                         mono_domain_unlock (cfg->domain);
8171
8172                         is_special_static = mono_class_field_is_special_static (field);
8173
8174                         /* Generate IR to compute the field address */
8175
8176                         if ((cfg->opt & MONO_OPT_SHARED) ||
8177                                         (cfg->compile_aot && is_special_static) ||
8178                                         (context_used && is_special_static)) {
8179                                 MonoInst *iargs [2];
8180
8181                                 g_assert (field->parent);
8182                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8183                                 if (context_used) {
8184                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
8185                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
8186                                 } else {
8187                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8188                                 }
8189                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8190                         } else if (context_used) {
8191                                 MonoInst *static_data;
8192
8193                                 /*
8194                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8195                                         method->klass->name_space, method->klass->name, method->name,
8196                                         depth, field->offset);
8197                                 */
8198
8199                                 if (mono_class_needs_cctor_run (klass, method)) {
8200                                         MonoCallInst *call;
8201                                         MonoInst *vtable;
8202
8203                                         vtable = emit_get_rgctx_klass (cfg, context_used,
8204                                                 klass, MONO_RGCTX_INFO_VTABLE);
8205
8206                                         // FIXME: This doesn't work since it tries to pass the argument
8207                                         // in the normal way, instead of using MONO_ARCH_VTABLE_REG
8208                                         /* 
8209                                          * The vtable pointer is always passed in a register regardless of
8210                                          * the calling convention, so assign it manually, and make a call
8211                                          * using a signature without parameters.
8212                                          */                                     
8213                                         call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable);
8214 #ifdef MONO_ARCH_VTABLE_REG
8215                                         mono_call_inst_add_outarg_reg (cfg, call, vtable->dreg, MONO_ARCH_VTABLE_REG, FALSE);
8216                                         cfg->uses_vtable_reg = TRUE;
8217 #else
8218                                         NOT_IMPLEMENTED;
8219 #endif
8220                                 }
8221
8222                                 /*
8223                                  * The pointer we're computing here is
8224                                  *
8225                                  *   super_info.static_data + field->offset
8226                                  */
8227                                 static_data = emit_get_rgctx_klass (cfg, context_used,
8228                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
8229
8230                                 if (field->offset == 0) {
8231                                         ins = static_data;
8232                                 } else {
8233                                         int addr_reg = mono_alloc_preg (cfg);
8234                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
8235                                 }
8236                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
8237                                 MonoInst *iargs [2];
8238
8239                                 g_assert (field->parent);
8240                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8241                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8242                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8243                         } else {
8244                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
8245
8246                                 CHECK_TYPELOAD (klass);
8247                                 if (!addr) {
8248                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8249                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
8250                                                 if (cfg->verbose_level > 2)
8251                                                         printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
8252                                                 class_inits = g_slist_prepend (class_inits, vtable);
8253                                         } else {
8254                                                 if (cfg->run_cctors) {
8255                                                         MonoException *ex;
8256                                                         /* This makes so that inline cannot trigger */
8257                                                         /* .cctors: too many apps depend on them */
8258                                                         /* running with a specific order... */
8259                                                         if (! vtable->initialized)
8260                                                                 INLINE_FAILURE;
8261                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8262                                                         if (ex) {
8263                                                                 set_exception_object (cfg, ex);
8264                                                                 goto exception_exit;
8265                                                         }
8266                                                 }
8267                                         }
8268                                         addr = (char*)vtable->data + field->offset;
8269
8270                                         if (cfg->compile_aot)
8271                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
8272                                         else
8273                                                 EMIT_NEW_PCONST (cfg, ins, addr);
8274                                 } else {
8275                                         /* 
8276                                          * insert call to mono_threads_get_static_data (GPOINTER_TO_UINT (addr)) 
8277                                          * This could be later optimized to do just a couple of
8278                                          * memory dereferences with constant offsets.
8279                                          */
8280                                         MonoInst *iargs [1];
8281                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8282                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
8283                                 }
8284                         }
8285
8286                         /* Generate IR to do the actual load/store operation */
8287
8288                         if (*ip == CEE_LDSFLDA) {
8289                                 ins->klass = mono_class_from_mono_type (field->type);
8290                                 ins->type = STACK_PTR;
8291                                 *sp++ = ins;
8292                         } else if (*ip == CEE_STSFLD) {
8293                                 MonoInst *store;
8294                                 CHECK_STACK (1);
8295                                 sp--;
8296
8297                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, ins->dreg, 0, sp [0]->dreg);
8298                                 store->flags |= ins_flag;
8299                         } else {
8300                                 gboolean is_const = FALSE;
8301                                 MonoVTable *vtable = NULL;
8302
8303                                 if (!context_used) {
8304                                         vtable = mono_class_vtable (cfg->domain, klass);
8305                                         CHECK_TYPELOAD (klass);
8306                                 }
8307                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8308                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8309                                         gpointer addr = (char*)vtable->data + field->offset;
8310                                         int ro_type = field->type->type;
8311                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8312                                                 ro_type = mono_class_enum_basetype (field->type->data.klass)->type;
8313                                         }
8314                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
8315                                         is_const = TRUE;
8316                                         switch (ro_type) {
8317                                         case MONO_TYPE_BOOLEAN:
8318                                         case MONO_TYPE_U1:
8319                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8320                                                 sp++;
8321                                                 break;
8322                                         case MONO_TYPE_I1:
8323                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8324                                                 sp++;
8325                                                 break;                                          
8326                                         case MONO_TYPE_CHAR:
8327                                         case MONO_TYPE_U2:
8328                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8329                                                 sp++;
8330                                                 break;
8331                                         case MONO_TYPE_I2:
8332                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8333                                                 sp++;
8334                                                 break;
8335                                                 break;
8336                                         case MONO_TYPE_I4:
8337                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8338                                                 sp++;
8339                                                 break;                                          
8340                                         case MONO_TYPE_U4:
8341                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8342                                                 sp++;
8343                                                 break;
8344 #ifndef HAVE_MOVING_COLLECTOR
8345                                         case MONO_TYPE_I:
8346                                         case MONO_TYPE_U:
8347                                         case MONO_TYPE_STRING:
8348                                         case MONO_TYPE_OBJECT:
8349                                         case MONO_TYPE_CLASS:
8350                                         case MONO_TYPE_SZARRAY:
8351                                         case MONO_TYPE_PTR:
8352                                         case MONO_TYPE_FNPTR:
8353                                         case MONO_TYPE_ARRAY:
8354                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8355                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
8356                                                 sp++;
8357                                                 break;
8358 #endif
8359                                         case MONO_TYPE_I8:
8360                                         case MONO_TYPE_U8:
8361                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
8362                                                 sp++;
8363                                                 break;
8364                                         case MONO_TYPE_R4:
8365                                         case MONO_TYPE_R8:
8366                                         case MONO_TYPE_VALUETYPE:
8367                                         default:
8368                                                 is_const = FALSE;
8369                                                 break;
8370                                         }
8371                                 }
8372
8373                                 if (!is_const) {
8374                                         MonoInst *load;
8375
8376                                         CHECK_STACK_OVF (1);
8377
8378                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
8379                                         load->flags |= ins_flag;
8380                                         ins_flag = 0;
8381                                         *sp++ = load;
8382                                 }
8383                         }
8384                         ins_flag = 0;
8385                         ip += 5;
8386                         break;
8387                 }
8388                 case CEE_STOBJ:
8389                         CHECK_STACK (2);
8390                         sp -= 2;
8391                         CHECK_OPSIZE (5);
8392                         token = read32 (ip + 1);
8393                         klass = mini_get_class (method, token, generic_context);
8394                         CHECK_TYPELOAD (klass);
8395                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8396                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
8397                         ins_flag = 0;
8398                         ip += 5;
8399                         inline_costs += 1;
8400                         break;
8401
8402                         /*
8403                          * Array opcodes
8404                          */
8405                 case CEE_NEWARR: {
8406                         MonoInst *len_ins;
8407                         const char *data_ptr;
8408                         int data_size = 0;
8409                         guint32 field_token;
8410
8411                         CHECK_STACK (1);
8412                         --sp;
8413
8414                         CHECK_OPSIZE (5);
8415                         token = read32 (ip + 1);
8416
8417                         klass = mini_get_class (method, token, generic_context);
8418                         CHECK_TYPELOAD (klass);
8419
8420                         if (cfg->generic_sharing_context)
8421                                 context_used = mono_class_check_context_used (klass);
8422
8423                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
8424                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
8425                                 ins->sreg1 = sp [0]->dreg;
8426                                 ins->type = STACK_I4;
8427                                 ins->dreg = alloc_ireg (cfg);
8428                                 MONO_ADD_INS (cfg->cbb, ins);
8429                                 *sp = mono_decompose_opcode (cfg, ins);
8430                         }
8431
8432                         if (context_used) {
8433                                 MonoInst *args [2];
8434
8435                                 /* FIXME: Decompose later to help abcrem */
8436
8437                                 /* vtable */
8438                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
8439                                         mono_array_class_get (klass, 1), MONO_RGCTX_INFO_VTABLE);
8440
8441                                 /* array len */
8442                                 args [1] = sp [0];
8443
8444                                 ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
8445                         } else {
8446                                 if (cfg->opt & MONO_OPT_SHARED) {
8447                                         /* Decompose now to avoid problems with references to the domainvar */
8448                                         MonoInst *iargs [3];
8449
8450                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8451                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8452                                         iargs [2] = sp [0];
8453
8454                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
8455                                 } else {
8456                                         /* Decompose later since it is needed by abcrem */
8457                                         MonoClass *array_type = mono_array_class_get (klass, 1);
8458                                         mono_class_vtable (cfg->domain, array_type);
8459                                         CHECK_TYPELOAD (array_type);
8460
8461                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
8462                                         ins->dreg = alloc_preg (cfg);
8463                                         ins->sreg1 = sp [0]->dreg;
8464                                         ins->inst_newa_class = klass;
8465                                         ins->type = STACK_OBJ;
8466                                         ins->klass = klass;
8467                                         MONO_ADD_INS (cfg->cbb, ins);
8468                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8469                                         cfg->cbb->has_array_access = TRUE;
8470
8471                                         /* Needed so mono_emit_load_get_addr () gets called */
8472                                         mono_get_got_var (cfg);
8473                                 }
8474                         }
8475
8476                         len_ins = sp [0];
8477                         ip += 5;
8478                         *sp++ = ins;
8479                         inline_costs += 1;
8480
8481                         /* 
8482                          * we inline/optimize the initialization sequence if possible.
8483                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8484                          * for small sizes open code the memcpy
8485                          * ensure the rva field is big enough
8486                          */
8487                         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))) {
8488                                 MonoMethod *memcpy_method = get_memcpy_method ();
8489                                 MonoInst *iargs [3];
8490                                 int add_reg = alloc_preg (cfg);
8491
8492                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
8493                                 if (cfg->compile_aot) {
8494                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
8495                                 } else {
8496                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8497                                 }
8498                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
8499                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
8500                                 ip += 11;
8501                         }
8502
8503                         break;
8504                 }
8505                 case CEE_LDLEN:
8506                         CHECK_STACK (1);
8507                         --sp;
8508                         if (sp [0]->type != STACK_OBJ)
8509                                 UNVERIFIED;
8510
8511                         dreg = alloc_preg (cfg);
8512                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
8513                         ins->dreg = alloc_preg (cfg);
8514                         ins->sreg1 = sp [0]->dreg;
8515                         ins->type = STACK_I4;
8516                         MONO_ADD_INS (cfg->cbb, ins);
8517                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8518                         cfg->cbb->has_array_access = TRUE;
8519                         ip ++;
8520                         *sp++ = ins;
8521                         break;
8522                 case CEE_LDELEMA:
8523                         CHECK_STACK (2);
8524                         sp -= 2;
8525                         CHECK_OPSIZE (5);
8526                         if (sp [0]->type != STACK_OBJ)
8527                                 UNVERIFIED;
8528
8529                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8530
8531                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8532                         CHECK_TYPELOAD (klass);
8533                         /* we need to make sure that this array is exactly the type it needs
8534                          * to be for correctness. the wrappers are lax with their usage
8535                          * so we need to ignore them here
8536                          */
8537                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8538                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8539                                 mini_emit_check_array_type (cfg, sp [0], array_class);
8540                                 CHECK_TYPELOAD (array_class);
8541                         }
8542
8543                         readonly = FALSE;
8544                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
8545                         *sp++ = ins;
8546                         ip += 5;
8547                         break;
8548                 case CEE_LDELEM:
8549                 case CEE_LDELEM_I1:
8550                 case CEE_LDELEM_U1:
8551                 case CEE_LDELEM_I2:
8552                 case CEE_LDELEM_U2:
8553                 case CEE_LDELEM_I4:
8554                 case CEE_LDELEM_U4:
8555                 case CEE_LDELEM_I8:
8556                 case CEE_LDELEM_I:
8557                 case CEE_LDELEM_R4:
8558                 case CEE_LDELEM_R8:
8559                 case CEE_LDELEM_REF: {
8560                         MonoInst *addr;
8561
8562                         CHECK_STACK (2);
8563                         sp -= 2;
8564
8565                         if (*ip == CEE_LDELEM) {
8566                                 CHECK_OPSIZE (5);
8567                                 token = read32 (ip + 1);
8568                                 klass = mini_get_class (method, token, generic_context);
8569                                 CHECK_TYPELOAD (klass);
8570                                 mono_class_init (klass);
8571                         }
8572                         else
8573                                 klass = array_access_to_klass (*ip);
8574
8575                         if (sp [0]->type != STACK_OBJ)
8576                                 UNVERIFIED;
8577
8578                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8579
8580                         if (sp [1]->opcode == OP_ICONST) {
8581                                 int array_reg = sp [0]->dreg;
8582                                 int index_reg = sp [1]->dreg;
8583                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
8584
8585                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
8586                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
8587                         } else {
8588                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
8589                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
8590                         }
8591                         *sp++ = ins;
8592                         if (*ip == CEE_LDELEM)
8593                                 ip += 5;
8594                         else
8595                                 ++ip;
8596                         break;
8597                 }
8598                 case CEE_STELEM_I:
8599                 case CEE_STELEM_I1:
8600                 case CEE_STELEM_I2:
8601                 case CEE_STELEM_I4:
8602                 case CEE_STELEM_I8:
8603                 case CEE_STELEM_R4:
8604                 case CEE_STELEM_R8:
8605                 case CEE_STELEM_REF:
8606                 case CEE_STELEM: {
8607                         MonoInst *addr;
8608
8609                         CHECK_STACK (3);
8610                         sp -= 3;
8611
8612                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8613
8614                         if (*ip == CEE_STELEM) {
8615                                 CHECK_OPSIZE (5);
8616                                 token = read32 (ip + 1);
8617                                 klass = mini_get_class (method, token, generic_context);
8618                                 CHECK_TYPELOAD (klass);
8619                                 mono_class_init (klass);
8620                         }
8621                         else
8622                                 klass = array_access_to_klass (*ip);
8623
8624                         if (sp [0]->type != STACK_OBJ)
8625                                 UNVERIFIED;
8626
8627                         /* storing a NULL doesn't need any of the complex checks in stelemref */
8628                         if (generic_class_is_reference_type (cfg, klass) &&
8629                                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
8630                                 MonoMethod* helper = mono_marshal_get_stelemref ();
8631                                 MonoInst *iargs [3];
8632
8633                                 if (sp [0]->type != STACK_OBJ)
8634                                         UNVERIFIED;
8635                                 if (sp [2]->type != STACK_OBJ)
8636                                         UNVERIFIED;
8637
8638                                 iargs [2] = sp [2];
8639                                 iargs [1] = sp [1];
8640                                 iargs [0] = sp [0];
8641                                 
8642                                 mono_emit_method_call (cfg, helper, iargs, NULL);
8643                         } else {
8644                                 if (sp [1]->opcode == OP_ICONST) {
8645                                         int array_reg = sp [0]->dreg;
8646                                         int index_reg = sp [1]->dreg;
8647                                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
8648
8649                                         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
8650                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
8651                                 } else {
8652                                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1]);
8653                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
8654                                 }
8655                         }
8656
8657                         if (*ip == CEE_STELEM)
8658                                 ip += 5;
8659                         else
8660                                 ++ip;
8661                         inline_costs += 1;
8662                         break;
8663                 }
8664                 case CEE_CKFINITE: {
8665                         CHECK_STACK (1);
8666                         --sp;
8667
8668                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
8669                         ins->sreg1 = sp [0]->dreg;
8670                         ins->dreg = alloc_freg (cfg);
8671                         ins->type = STACK_R8;
8672                         MONO_ADD_INS (bblock, ins);
8673
8674                         *sp++ = mono_decompose_opcode (cfg, ins);
8675
8676                         ++ip;
8677                         break;
8678                 }
8679                 case CEE_REFANYVAL: {
8680                         MonoInst *src_var, *src;
8681
8682                         int klass_reg = alloc_preg (cfg);
8683                         int dreg = alloc_preg (cfg);
8684
8685                         CHECK_STACK (1);
8686                         MONO_INST_NEW (cfg, ins, *ip);
8687                         --sp;
8688                         CHECK_OPSIZE (5);
8689                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8690                         CHECK_TYPELOAD (klass);
8691                         mono_class_init (klass);
8692
8693                         if (cfg->generic_sharing_context)
8694                                 context_used = mono_class_check_context_used (klass);
8695
8696                         // FIXME:
8697                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
8698                         if (!src_var)
8699                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
8700                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
8701                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
8702
8703                         if (context_used) {
8704                                 MonoInst *klass_ins;
8705
8706                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
8707                                                 klass, MONO_RGCTX_INFO_KLASS);
8708
8709                                 // FIXME:
8710                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
8711                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
8712                         } else {
8713                                 mini_emit_class_check (cfg, klass_reg, klass);
8714                         }
8715                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
8716                         ins->type = STACK_MP;
8717                         *sp++ = ins;
8718                         ip += 5;
8719                         break;
8720                 }
8721                 case CEE_MKREFANY: {
8722                         MonoInst *loc, *addr;
8723
8724                         CHECK_STACK (1);
8725                         MONO_INST_NEW (cfg, ins, *ip);
8726                         --sp;
8727                         CHECK_OPSIZE (5);
8728                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
8729                         CHECK_TYPELOAD (klass);
8730                         mono_class_init (klass);
8731
8732                         if (cfg->generic_sharing_context)
8733                                 context_used = mono_class_check_context_used (klass);
8734
8735                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
8736                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
8737
8738                         if (context_used) {
8739                                 MonoInst *const_ins;
8740                                 int type_reg = alloc_preg (cfg);
8741
8742                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
8743                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
8744                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
8745                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
8746                         } else if (cfg->compile_aot) {
8747                                 int const_reg = alloc_preg (cfg);
8748                                 int type_reg = alloc_preg (cfg);
8749
8750                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
8751                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
8752                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
8753                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
8754                         } else {
8755                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
8756                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
8757                         }
8758                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
8759
8760                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
8761                         ins->type = STACK_VTYPE;
8762                         ins->klass = mono_defaults.typed_reference_class;
8763                         *sp++ = ins;
8764                         ip += 5;
8765                         break;
8766                 }
8767                 case CEE_LDTOKEN: {
8768                         gpointer handle;
8769                         MonoClass *handle_class;
8770
8771                         CHECK_STACK_OVF (1);
8772
8773                         CHECK_OPSIZE (5);
8774                         n = read32 (ip + 1);
8775
8776                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
8777                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8778                                 handle = mono_method_get_wrapper_data (method, n);
8779                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
8780                                 if (handle_class == mono_defaults.typehandle_class)
8781                                         handle = &((MonoClass*)handle)->byval_arg;
8782                         }
8783                         else {
8784                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
8785                         }
8786                         if (!handle)
8787                                 goto load_error;
8788                         mono_class_init (handle_class);
8789                         if (cfg->generic_sharing_context) {
8790                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
8791                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
8792                                         /* This case handles ldtoken
8793                                            of an open type, like for
8794                                            typeof(Gen<>). */
8795                                         context_used = 0;
8796                                 } else if (handle_class == mono_defaults.typehandle_class) {
8797                                         /* If we get a MONO_TYPE_CLASS
8798                                            then we need to provide the
8799                                            open type, not an
8800                                            instantiation of it. */
8801                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
8802                                                 context_used = 0;
8803                                         else
8804                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
8805                                 } else if (handle_class == mono_defaults.fieldhandle_class)
8806                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
8807                                 else if (handle_class == mono_defaults.methodhandle_class)
8808                                         context_used = mono_method_check_context_used (handle);
8809                                 else
8810                                         g_assert_not_reached ();
8811                         }
8812
8813                         if ((cfg->opt & MONO_OPT_SHARED) &&
8814                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
8815                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
8816                                 MonoInst *addr, *vtvar, *iargs [3];
8817                                 int method_context_used;
8818
8819                                 if (cfg->generic_sharing_context)
8820                                         method_context_used = mono_method_check_context_used (method);
8821                                 else
8822                                         method_context_used = 0;
8823
8824                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
8825
8826                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
8827                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
8828                                 if (method_context_used) {
8829                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
8830                                                 method, MONO_RGCTX_INFO_METHOD);
8831                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
8832                                 } else {
8833                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
8834                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
8835                                 }
8836                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8837
8838                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8839
8840                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8841                         } else {
8842                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
8843                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
8844                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
8845                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
8846                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
8847                                         MonoClass *tclass = mono_class_from_mono_type (handle);
8848
8849                                         mono_class_init (tclass);
8850                                         if (context_used) {
8851                                                 ins = emit_get_rgctx_klass (cfg, context_used,
8852                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
8853                                         } else if (cfg->compile_aot) {
8854                                                 if (method->wrapper_type) {
8855                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
8856                                                                 /* Special case for static synchronized wrappers */
8857                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
8858                                                         } else {
8859                                                                 /* FIXME: n is not a normal token */
8860                                                                 cfg->disable_aot = TRUE;
8861                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
8862                                                         }
8863                                                 } else {
8864                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
8865                                                 }
8866                                         } else {
8867                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
8868                                         }
8869                                         ins->type = STACK_OBJ;
8870                                         ins->klass = cmethod->klass;
8871                                         ip += 5;
8872                                 } else {
8873                                         MonoInst *addr, *vtvar;
8874
8875                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
8876
8877                                         if (context_used) {
8878                                                 if (handle_class == mono_defaults.typehandle_class) {
8879                                                         ins = emit_get_rgctx_klass (cfg, context_used,
8880                                                                         mono_class_from_mono_type (handle),
8881                                                                         MONO_RGCTX_INFO_TYPE);
8882                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
8883                                                         ins = emit_get_rgctx_method (cfg, context_used,
8884                                                                         handle, MONO_RGCTX_INFO_METHOD);
8885                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
8886                                                         ins = emit_get_rgctx_field (cfg, context_used,
8887                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
8888                                                 } else {
8889                                                         g_assert_not_reached ();
8890                                                 }
8891                                         } else if (cfg->compile_aot) {
8892                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n);
8893                                         } else {
8894                                                 EMIT_NEW_PCONST (cfg, ins, handle);
8895                                         }
8896                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
8897                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
8898                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
8899                                 }
8900                         }
8901
8902                         *sp++ = ins;
8903                         ip += 5;
8904                         break;
8905                 }
8906                 case CEE_THROW:
8907                         CHECK_STACK (1);
8908                         MONO_INST_NEW (cfg, ins, OP_THROW);
8909                         --sp;
8910                         ins->sreg1 = sp [0]->dreg;
8911                         ip++;
8912                         bblock->out_of_line = TRUE;
8913                         MONO_ADD_INS (bblock, ins);
8914                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
8915                         MONO_ADD_INS (bblock, ins);
8916                         sp = stack_start;
8917                         
8918                         link_bblock (cfg, bblock, end_bblock);
8919                         start_new_bblock = 1;
8920                         break;
8921                 case CEE_ENDFINALLY:
8922                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
8923                         MONO_ADD_INS (bblock, ins);
8924                         ip++;
8925                         start_new_bblock = 1;
8926
8927                         /*
8928                          * Control will leave the method so empty the stack, otherwise
8929                          * the next basic block will start with a nonempty stack.
8930                          */
8931                         while (sp != stack_start) {
8932                                 sp--;
8933                         }
8934                         break;
8935                 case CEE_LEAVE:
8936                 case CEE_LEAVE_S: {
8937                         GList *handlers;
8938
8939                         if (*ip == CEE_LEAVE) {
8940                                 CHECK_OPSIZE (5);
8941                                 target = ip + 5 + (gint32)read32(ip + 1);
8942                         } else {
8943                                 CHECK_OPSIZE (2);
8944                                 target = ip + 2 + (signed char)(ip [1]);
8945                         }
8946
8947                         /* empty the stack */
8948                         while (sp != stack_start) {
8949                                 sp--;
8950                         }
8951
8952                         /* 
8953                          * If this leave statement is in a catch block, check for a
8954                          * pending exception, and rethrow it if necessary.
8955                          */
8956                         for (i = 0; i < header->num_clauses; ++i) {
8957                                 MonoExceptionClause *clause = &header->clauses [i];
8958
8959                                 /* 
8960                                  * Use <= in the final comparison to handle clauses with multiple
8961                                  * leave statements, like in bug #78024.
8962                                  * The ordering of the exception clauses guarantees that we find the
8963                                  * innermost clause.
8964                                  */
8965                                 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)) {
8966                                         MonoInst *exc_ins;
8967                                         MonoBasicBlock *dont_throw;
8968
8969                                         /*
8970                                           MonoInst *load;
8971
8972                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
8973                                         */
8974
8975                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
8976
8977                                         NEW_BBLOCK (cfg, dont_throw);
8978
8979                                         /*
8980                                          * Currently, we allways rethrow the abort exception, despite the 
8981                                          * fact that this is not correct. See thread6.cs for an example. 
8982                                          * But propagating the abort exception is more important than 
8983                                          * getting the sematics right.
8984                                          */
8985                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
8986                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
8987                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
8988
8989                                         MONO_START_BB (cfg, dont_throw);
8990                                         bblock = cfg->cbb;
8991                                 }
8992                         }
8993
8994                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
8995                                 GList *tmp;
8996                                 for (tmp = handlers; tmp; tmp = tmp->next) {
8997                                         tblock = tmp->data;
8998                                         link_bblock (cfg, bblock, tblock);
8999                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9000                                         ins->inst_target_bb = tblock;
9001                                         MONO_ADD_INS (bblock, ins);
9002                                         bblock->has_call_handler = 1;
9003                                 }
9004                                 g_list_free (handlers);
9005                         } 
9006
9007                         MONO_INST_NEW (cfg, ins, OP_BR);
9008                         MONO_ADD_INS (bblock, ins);
9009                         GET_BBLOCK (cfg, tblock, target);
9010                         link_bblock (cfg, bblock, tblock);
9011                         ins->inst_target_bb = tblock;
9012                         start_new_bblock = 1;
9013
9014                         if (*ip == CEE_LEAVE)
9015                                 ip += 5;
9016                         else
9017                                 ip += 2;
9018
9019                         break;
9020                 }
9021
9022                         /*
9023                          * Mono specific opcodes
9024                          */
9025                 case MONO_CUSTOM_PREFIX: {
9026
9027                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9028
9029                         CHECK_OPSIZE (2);
9030                         switch (ip [1]) {
9031                         case CEE_MONO_ICALL: {
9032                                 gpointer func;
9033                                 MonoJitICallInfo *info;
9034
9035                                 token = read32 (ip + 2);
9036                                 func = mono_method_get_wrapper_data (method, token);
9037                                 info = mono_find_jit_icall_by_addr (func);
9038                                 g_assert (info);
9039
9040                                 CHECK_STACK (info->sig->param_count);
9041                                 sp -= info->sig->param_count;
9042
9043                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
9044                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
9045                                         *sp++ = ins;
9046
9047                                 ip += 6;
9048                                 inline_costs += 10 * num_calls++;
9049
9050                                 break;
9051                         }
9052                         case CEE_MONO_LDPTR: {
9053                                 gpointer ptr;
9054
9055                                 CHECK_STACK_OVF (1);
9056                                 CHECK_OPSIZE (6);
9057                                 token = read32 (ip + 2);
9058
9059                                 ptr = mono_method_get_wrapper_data (method, token);
9060                                 if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9061                                         MonoJitICallInfo *callinfo;
9062                                         const char *icall_name;
9063
9064                                         icall_name = method->name + strlen ("__icall_wrapper_");
9065                                         g_assert (icall_name);
9066                                         callinfo = mono_find_jit_icall_by_name (icall_name);
9067                                         g_assert (callinfo);
9068                                                 
9069                                         if (ptr == callinfo->func) {
9070                                                 /* Will be transformed into an AOTCONST later */
9071                                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9072                                                 *sp++ = ins;
9073                                                 ip += 6;
9074                                                 break;
9075                                         }
9076                                 }
9077                                 /* FIXME: Generalize this */
9078                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9079                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9080                                         *sp++ = ins;
9081                                         ip += 6;
9082                                         break;
9083                                 }
9084                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9085                                 *sp++ = ins;
9086                                 ip += 6;
9087                                 inline_costs += 10 * num_calls++;
9088                                 /* Can't embed random pointers into AOT code */
9089                                 cfg->disable_aot = 1;
9090                                 break;
9091                         }
9092                         case CEE_MONO_ICALL_ADDR: {
9093                                 MonoMethod *cmethod;
9094                                 gpointer ptr;
9095
9096                                 CHECK_STACK_OVF (1);
9097                                 CHECK_OPSIZE (6);
9098                                 token = read32 (ip + 2);
9099
9100                                 cmethod = mono_method_get_wrapper_data (method, token);
9101
9102                                 if (cfg->compile_aot) {
9103                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9104                                 } else {
9105                                         ptr = mono_lookup_internal_call (cmethod);
9106                                         g_assert (ptr);
9107                                         EMIT_NEW_PCONST (cfg, ins, ptr);
9108                                 }
9109                                 *sp++ = ins;
9110                                 ip += 6;
9111                                 break;
9112                         }
9113                         case CEE_MONO_VTADDR: {
9114                                 MonoInst *src_var, *src;
9115
9116                                 CHECK_STACK (1);
9117                                 --sp;
9118
9119                                 // FIXME:
9120                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9121                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
9122                                 *sp++ = src;
9123                                 ip += 2;
9124                                 break;
9125                         }
9126                         case CEE_MONO_NEWOBJ: {
9127                                 MonoInst *iargs [2];
9128
9129                                 CHECK_STACK_OVF (1);
9130                                 CHECK_OPSIZE (6);
9131                                 token = read32 (ip + 2);
9132                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9133                                 mono_class_init (klass);
9134                                 NEW_DOMAINCONST (cfg, iargs [0]);
9135                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
9136                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9137                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
9138                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
9139                                 ip += 6;
9140                                 inline_costs += 10 * num_calls++;
9141                                 break;
9142                         }
9143                         case CEE_MONO_OBJADDR:
9144                                 CHECK_STACK (1);
9145                                 --sp;
9146                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
9147                                 ins->dreg = alloc_preg (cfg);
9148                                 ins->sreg1 = sp [0]->dreg;
9149                                 ins->type = STACK_MP;
9150                                 MONO_ADD_INS (cfg->cbb, ins);
9151                                 *sp++ = ins;
9152                                 ip += 2;
9153                                 break;
9154                         case CEE_MONO_LDNATIVEOBJ:
9155                                 /*
9156                                  * Similar to LDOBJ, but instead load the unmanaged 
9157                                  * representation of the vtype to the stack.
9158                                  */
9159                                 CHECK_STACK (1);
9160                                 CHECK_OPSIZE (6);
9161                                 --sp;
9162                                 token = read32 (ip + 2);
9163                                 klass = mono_method_get_wrapper_data (method, token);
9164                                 g_assert (klass->valuetype);
9165                                 mono_class_init (klass);
9166
9167                                 {
9168                                         MonoInst *src, *dest, *temp;
9169
9170                                         src = sp [0];
9171                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
9172                                         temp->backend.is_pinvoke = 1;
9173                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
9174                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
9175
9176                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
9177                                         dest->type = STACK_VTYPE;
9178                                         dest->klass = klass;
9179
9180                                         *sp ++ = dest;
9181                                         ip += 6;
9182                                 }
9183                                 break;
9184                         case CEE_MONO_RETOBJ: {
9185                                 /*
9186                                  * Same as RET, but return the native representation of a vtype
9187                                  * to the caller.
9188                                  */
9189                                 g_assert (cfg->ret);
9190                                 g_assert (mono_method_signature (method)->pinvoke); 
9191                                 CHECK_STACK (1);
9192                                 --sp;
9193                                 
9194                                 CHECK_OPSIZE (6);
9195                                 token = read32 (ip + 2);    
9196                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9197
9198                                 if (!cfg->vret_addr) {
9199                                         g_assert (cfg->ret_var_is_local);
9200
9201                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
9202                                 } else {
9203                                         EMIT_NEW_RETLOADA (cfg, ins);
9204                                 }
9205                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
9206                                 
9207                                 if (sp != stack_start)
9208                                         UNVERIFIED;
9209                                 
9210                                 MONO_INST_NEW (cfg, ins, OP_BR);
9211                                 ins->inst_target_bb = end_bblock;
9212                                 MONO_ADD_INS (bblock, ins);
9213                                 link_bblock (cfg, bblock, end_bblock);
9214                                 start_new_bblock = 1;
9215                                 ip += 6;
9216                                 break;
9217                         }
9218                         case CEE_MONO_CISINST:
9219                         case CEE_MONO_CCASTCLASS: {
9220                                 int token;
9221                                 CHECK_STACK (1);
9222                                 --sp;
9223                                 CHECK_OPSIZE (6);
9224                                 token = read32 (ip + 2);
9225                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9226                                 if (ip [1] == CEE_MONO_CISINST)
9227                                         ins = handle_cisinst (cfg, klass, sp [0]);
9228                                 else
9229                                         ins = handle_ccastclass (cfg, klass, sp [0]);
9230                                 bblock = cfg->cbb;
9231                                 *sp++ = ins;
9232                                 ip += 6;
9233                                 break;
9234                         }
9235                         case CEE_MONO_SAVE_LMF:
9236                         case CEE_MONO_RESTORE_LMF:
9237 #ifdef MONO_ARCH_HAVE_LMF_OPS
9238                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9239                                 MONO_ADD_INS (bblock, ins);
9240                                 cfg->need_lmf_area = TRUE;
9241 #endif
9242                                 ip += 2;
9243                                 break;
9244                         case CEE_MONO_CLASSCONST:
9245                                 CHECK_STACK_OVF (1);
9246                                 CHECK_OPSIZE (6);
9247                                 token = read32 (ip + 2);
9248                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9249                                 *sp++ = ins;
9250                                 ip += 6;
9251                                 inline_costs += 10 * num_calls++;
9252                                 break;
9253                         case CEE_MONO_NOT_TAKEN:
9254                                 bblock->out_of_line = TRUE;
9255                                 ip += 2;
9256                                 break;
9257                         case CEE_MONO_TLS:
9258                                 CHECK_STACK_OVF (1);
9259                                 CHECK_OPSIZE (6);
9260                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9261                                 ins->dreg = alloc_preg (cfg);
9262                                 ins->inst_offset = (gint32)read32 (ip + 2);
9263                                 ins->type = STACK_PTR;
9264                                 MONO_ADD_INS (bblock, ins);
9265                                 *sp++ = ins;
9266                                 ip += 6;
9267                                 break;
9268                         case CEE_MONO_DYN_CALL: {
9269                                 MonoCallInst *call;
9270
9271                                 /* It would be easier to call a trampoline, but that would put an
9272                                  * extra frame on the stack, confusing exception handling. So
9273                                  * implement it inline using an opcode for now.
9274                                  */
9275
9276                                 if (!cfg->dyn_call_var) {
9277                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9278                                         /* prevent it from being register allocated */
9279                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
9280                                 }
9281
9282                                 /* Has to use a call inst since it local regalloc expects it */
9283                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
9284                                 ins = (MonoInst*)call;
9285                                 sp -= 2;
9286                                 ins->sreg1 = sp [0]->dreg;
9287                                 ins->sreg2 = sp [1]->dreg;
9288                                 MONO_ADD_INS (bblock, ins);
9289
9290 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
9291                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
9292 #endif
9293
9294                                 ip += 2;
9295                                 inline_costs += 10 * num_calls++;
9296
9297                                 break;
9298                         }
9299                         default:
9300                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9301                                 break;
9302                         }
9303                         break;
9304                 }
9305
9306                 case CEE_PREFIX1: {
9307                         CHECK_OPSIZE (2);
9308                         switch (ip [1]) {
9309                         case CEE_ARGLIST: {
9310                                 /* somewhat similar to LDTOKEN */
9311                                 MonoInst *addr, *vtvar;
9312                                 CHECK_STACK_OVF (1);
9313                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9314
9315                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9316                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
9317
9318                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9319                                 ins->type = STACK_VTYPE;
9320                                 ins->klass = mono_defaults.argumenthandle_class;
9321                                 *sp++ = ins;
9322                                 ip += 2;
9323                                 break;
9324                         }
9325                         case CEE_CEQ:
9326                         case CEE_CGT:
9327                         case CEE_CGT_UN:
9328                         case CEE_CLT:
9329                         case CEE_CLT_UN: {
9330                                 MonoInst *cmp;
9331                                 CHECK_STACK (2);
9332                                 /*
9333                                  * The following transforms:
9334                                  *    CEE_CEQ    into OP_CEQ
9335                                  *    CEE_CGT    into OP_CGT
9336                                  *    CEE_CGT_UN into OP_CGT_UN
9337                                  *    CEE_CLT    into OP_CLT
9338                                  *    CEE_CLT_UN into OP_CLT_UN
9339                                  */
9340                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9341                                 
9342                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9343                                 sp -= 2;
9344                                 cmp->sreg1 = sp [0]->dreg;
9345                                 cmp->sreg2 = sp [1]->dreg;
9346                                 type_from_op (cmp, sp [0], sp [1]);
9347                                 CHECK_TYPE (cmp);
9348                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9349                                         cmp->opcode = OP_LCOMPARE;
9350                                 else if (sp [0]->type == STACK_R8)
9351                                         cmp->opcode = OP_FCOMPARE;
9352                                 else
9353                                         cmp->opcode = OP_ICOMPARE;
9354                                 MONO_ADD_INS (bblock, cmp);
9355                                 ins->type = STACK_I4;
9356                                 ins->dreg = alloc_dreg (cfg, ins->type);
9357                                 type_from_op (ins, sp [0], sp [1]);
9358
9359                                 if (cmp->opcode == OP_FCOMPARE) {
9360                                         /*
9361                                          * The backends expect the fceq opcodes to do the
9362                                          * comparison too.
9363                                          */
9364                                         cmp->opcode = OP_NOP;
9365                                         ins->sreg1 = cmp->sreg1;
9366                                         ins->sreg2 = cmp->sreg2;
9367                                 }
9368                                 MONO_ADD_INS (bblock, ins);
9369                                 *sp++ = ins;
9370                                 ip += 2;
9371                                 break;
9372                         }
9373                         case CEE_LDFTN: {
9374                                 MonoInst *argconst;
9375                                 MonoMethod *cil_method;
9376                                 gboolean needs_static_rgctx_invoke;
9377
9378                                 CHECK_STACK_OVF (1);
9379                                 CHECK_OPSIZE (6);
9380                                 n = read32 (ip + 2);
9381                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9382                                 if (!cmethod)
9383                                         goto load_error;
9384                                 mono_class_init (cmethod->klass);
9385
9386                                 mono_save_token_info (cfg, image, n, cmethod);
9387
9388                                 if (cfg->generic_sharing_context)
9389                                         context_used = mono_method_check_context_used (cmethod);
9390
9391                                 needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
9392  
9393                                 cil_method = cmethod;
9394                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9395                                         METHOD_ACCESS_FAILURE;
9396
9397                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9398                                         if (check_linkdemand (cfg, method, cmethod))
9399                                                 INLINE_FAILURE;
9400                                         CHECK_CFG_EXCEPTION;
9401                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9402                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9403                                 }
9404
9405                                 /* 
9406                                  * Optimize the common case of ldftn+delegate creation
9407                                  */
9408 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE) && !defined(HAVE_WRITE_BARRIERS)
9409                                 /* FIXME: SGEN support */
9410                                 /* FIXME: handle shared static generic methods */
9411                                 /* FIXME: handle this in shared code */
9412                                 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)) {
9413                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
9414                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9415                                                 MonoInst *target_ins;
9416                                                 MonoMethod *invoke;
9417
9418                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
9419                                                 if (!invoke || !mono_method_signature (invoke))
9420                                                         goto load_error;
9421
9422                                                 ip += 6;
9423                                                 if (cfg->verbose_level > 3)
9424                                                         g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9425                                                 target_ins = sp [-1];
9426                                                 sp --;
9427                                                 *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod);
9428                                                 CHECK_CFG_EXCEPTION;
9429                                                 ip += 5;                        
9430                                                 sp ++;
9431                                                 break;
9432                                         }
9433                                 }
9434 #endif
9435
9436                                 if (context_used) {
9437                                         argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
9438                                 } else {
9439                                         EMIT_NEW_METHODCONST (cfg, argconst, cmethod);
9440                                 }
9441                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
9442                                 *sp++ = ins;
9443                                 
9444                                 ip += 6;
9445                                 inline_costs += 10 * num_calls++;
9446                                 break;
9447                         }
9448                         case CEE_LDVIRTFTN: {
9449                                 MonoInst *args [2];
9450
9451                                 CHECK_STACK (1);
9452                                 CHECK_OPSIZE (6);
9453                                 n = read32 (ip + 2);
9454                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9455                                 if (!cmethod)
9456                                         goto load_error;
9457                                 mono_class_init (cmethod->klass);
9458  
9459                                 if (cfg->generic_sharing_context)
9460                                         context_used = mono_method_check_context_used (cmethod);
9461
9462                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9463                                         if (check_linkdemand (cfg, method, cmethod))
9464                                                 INLINE_FAILURE;
9465                                         CHECK_CFG_EXCEPTION;
9466                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9467                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9468                                 }
9469
9470                                 --sp;
9471                                 args [0] = *sp;
9472
9473                                 if (context_used) {
9474                                         args [1] = emit_get_rgctx_method (cfg, context_used,
9475                                                 cmethod, MONO_RGCTX_INFO_METHOD);
9476                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
9477                                 } else {
9478                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
9479                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
9480                                 }
9481
9482                                 ip += 6;
9483                                 inline_costs += 10 * num_calls++;
9484                                 break;
9485                         }
9486                         case CEE_LDARG:
9487                                 CHECK_STACK_OVF (1);
9488                                 CHECK_OPSIZE (4);
9489                                 n = read16 (ip + 2);
9490                                 CHECK_ARG (n);
9491                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
9492                                 *sp++ = ins;
9493                                 ip += 4;
9494                                 break;
9495                         case CEE_LDARGA:
9496                                 CHECK_STACK_OVF (1);
9497                                 CHECK_OPSIZE (4);
9498                                 n = read16 (ip + 2);
9499                                 CHECK_ARG (n);
9500                                 NEW_ARGLOADA (cfg, ins, n);
9501                                 MONO_ADD_INS (cfg->cbb, ins);
9502                                 *sp++ = ins;
9503                                 ip += 4;
9504                                 break;
9505                         case CEE_STARG:
9506                                 CHECK_STACK (1);
9507                                 --sp;
9508                                 CHECK_OPSIZE (4);
9509                                 n = read16 (ip + 2);
9510                                 CHECK_ARG (n);
9511                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9512                                         UNVERIFIED;
9513                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
9514                                 ip += 4;
9515                                 break;
9516                         case CEE_LDLOC:
9517                                 CHECK_STACK_OVF (1);
9518                                 CHECK_OPSIZE (4);
9519                                 n = read16 (ip + 2);
9520                                 CHECK_LOCAL (n);
9521                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
9522                                 *sp++ = ins;
9523                                 ip += 4;
9524                                 break;
9525                         case CEE_LDLOCA: {
9526                                 unsigned char *tmp_ip;
9527                                 CHECK_STACK_OVF (1);
9528                                 CHECK_OPSIZE (4);
9529                                 n = read16 (ip + 2);
9530                                 CHECK_LOCAL (n);
9531
9532                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
9533                                         ip = tmp_ip;
9534                                         inline_costs += 1;
9535                                         break;
9536                                 }                       
9537                                 
9538                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
9539                                 *sp++ = ins;
9540                                 ip += 4;
9541                                 break;
9542                         }
9543                         case CEE_STLOC:
9544                                 CHECK_STACK (1);
9545                                 --sp;
9546                                 CHECK_OPSIZE (4);
9547                                 n = read16 (ip + 2);
9548                                 CHECK_LOCAL (n);
9549                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
9550                                         UNVERIFIED;
9551                                 emit_stloc_ir (cfg, sp, header, n);
9552                                 ip += 4;
9553                                 inline_costs += 1;
9554                                 break;
9555                         case CEE_LOCALLOC:
9556                                 CHECK_STACK (1);
9557                                 --sp;
9558                                 if (sp != stack_start) 
9559                                         UNVERIFIED;
9560                                 if (cfg->method != method) 
9561                                         /* 
9562                                          * Inlining this into a loop in a parent could lead to 
9563                                          * stack overflows which is different behavior than the
9564                                          * non-inlined case, thus disable inlining in this case.
9565                                          */
9566                                         goto inline_failure;
9567
9568                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
9569                                 ins->dreg = alloc_preg (cfg);
9570                                 ins->sreg1 = sp [0]->dreg;
9571                                 ins->type = STACK_PTR;
9572                                 MONO_ADD_INS (cfg->cbb, ins);
9573
9574                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
9575                                 if (init_locals)
9576                                         ins->flags |= MONO_INST_INIT;
9577
9578                                 *sp++ = ins;
9579                                 ip += 2;
9580                                 break;
9581                         case CEE_ENDFILTER: {
9582                                 MonoExceptionClause *clause, *nearest;
9583                                 int cc, nearest_num;
9584
9585                                 CHECK_STACK (1);
9586                                 --sp;
9587                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
9588                                         UNVERIFIED;
9589                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
9590                                 ins->sreg1 = (*sp)->dreg;
9591                                 MONO_ADD_INS (bblock, ins);
9592                                 start_new_bblock = 1;
9593                                 ip += 2;
9594
9595                                 nearest = NULL;
9596                                 nearest_num = 0;
9597                                 for (cc = 0; cc < header->num_clauses; ++cc) {
9598                                         clause = &header->clauses [cc];
9599                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
9600                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
9601                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
9602                                                 nearest = clause;
9603                                                 nearest_num = cc;
9604                                         }
9605                                 }
9606                                 g_assert (nearest);
9607                                 if ((ip - header->code) != nearest->handler_offset)
9608                                         UNVERIFIED;
9609
9610                                 break;
9611                         }
9612                         case CEE_UNALIGNED_:
9613                                 ins_flag |= MONO_INST_UNALIGNED;
9614                                 /* FIXME: record alignment? we can assume 1 for now */
9615                                 CHECK_OPSIZE (3);
9616                                 ip += 3;
9617                                 break;
9618                         case CEE_VOLATILE_:
9619                                 ins_flag |= MONO_INST_VOLATILE;
9620                                 ip += 2;
9621                                 break;
9622                         case CEE_TAIL_:
9623                                 ins_flag   |= MONO_INST_TAILCALL;
9624                                 cfg->flags |= MONO_CFG_HAS_TAIL;
9625                                 /* Can't inline tail calls at this time */
9626                                 inline_costs += 100000;
9627                                 ip += 2;
9628                                 break;
9629                         case CEE_INITOBJ:
9630                                 CHECK_STACK (1);
9631                                 --sp;
9632                                 CHECK_OPSIZE (6);
9633                                 token = read32 (ip + 2);
9634                                 klass = mini_get_class (method, token, generic_context);
9635                                 CHECK_TYPELOAD (klass);
9636                                 if (generic_class_is_reference_type (cfg, klass))
9637                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
9638                                 else
9639                                         mini_emit_initobj (cfg, *sp, NULL, klass);
9640                                 ip += 6;
9641                                 inline_costs += 1;
9642                                 break;
9643                         case CEE_CONSTRAINED_:
9644                                 CHECK_OPSIZE (6);
9645                                 token = read32 (ip + 2);
9646                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
9647                                         constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
9648                                 else
9649                                         constrained_call = mono_class_get_full (image, token, generic_context);
9650                                 CHECK_TYPELOAD (constrained_call);
9651                                 ip += 6;
9652                                 break;
9653                         case CEE_CPBLK:
9654                         case CEE_INITBLK: {
9655                                 MonoInst *iargs [3];
9656                                 CHECK_STACK (3);
9657                                 sp -= 3;
9658
9659                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
9660                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
9661                                 } 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)) {
9662                                         /* emit_memset only works when val == 0 */
9663                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
9664                                 } else {
9665                                         iargs [0] = sp [0];
9666                                         iargs [1] = sp [1];
9667                                         iargs [2] = sp [2];
9668                                         if (ip [1] == CEE_CPBLK) {
9669                                                 MonoMethod *memcpy_method = get_memcpy_method ();
9670                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
9671                                         } else {
9672                                                 MonoMethod *memset_method = get_memset_method ();
9673                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
9674                                         }
9675                                 }
9676                                 ip += 2;
9677                                 inline_costs += 1;
9678                                 break;
9679                         }
9680                         case CEE_NO_:
9681                                 CHECK_OPSIZE (3);
9682                                 if (ip [2] & 0x1)
9683                                         ins_flag |= MONO_INST_NOTYPECHECK;
9684                                 if (ip [2] & 0x2)
9685                                         ins_flag |= MONO_INST_NORANGECHECK;
9686                                 /* we ignore the no-nullcheck for now since we
9687                                  * really do it explicitly only when doing callvirt->call
9688                                  */
9689                                 ip += 3;
9690                                 break;
9691                         case CEE_RETHROW: {
9692                                 MonoInst *load;
9693                                 int handler_offset = -1;
9694
9695                                 for (i = 0; i < header->num_clauses; ++i) {
9696                                         MonoExceptionClause *clause = &header->clauses [i];
9697                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
9698                                                 handler_offset = clause->handler_offset;
9699                                                 break;
9700                                         }
9701                                 }
9702
9703                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
9704
9705                                 g_assert (handler_offset != -1);
9706
9707                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
9708                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
9709                                 ins->sreg1 = load->dreg;
9710                                 MONO_ADD_INS (bblock, ins);
9711                                 sp = stack_start;
9712                                 link_bblock (cfg, bblock, end_bblock);
9713                                 start_new_bblock = 1;
9714                                 ip += 2;
9715                                 break;
9716                         }
9717                         case CEE_SIZEOF: {
9718                                 guint32 align;
9719                                 int ialign;
9720
9721                                 CHECK_STACK_OVF (1);
9722                                 CHECK_OPSIZE (6);
9723                                 token = read32 (ip + 2);
9724                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC) {
9725                                         MonoType *type = mono_type_create_from_typespec (image, token);
9726                                         token = mono_type_size (type, &ialign);
9727                                 } else {
9728                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
9729                                         CHECK_TYPELOAD (klass);
9730                                         mono_class_init (klass);
9731                                         token = mono_class_value_size (klass, &align);
9732                                 }
9733                                 EMIT_NEW_ICONST (cfg, ins, token);
9734                                 *sp++= ins;
9735                                 ip += 6;
9736                                 break;
9737                         }
9738                         case CEE_REFANYTYPE: {
9739                                 MonoInst *src_var, *src;
9740
9741                                 CHECK_STACK (1);
9742                                 --sp;
9743
9744                                 // FIXME:
9745                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9746                                 if (!src_var)
9747                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
9748                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
9749                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
9750                                 *sp++ = ins;
9751                                 ip += 2;
9752                                 break;
9753                         }
9754                         case CEE_READONLY_:
9755                                 readonly = TRUE;
9756                                 ip += 2;
9757                                 break;
9758                         default:
9759                                 g_error ("opcode 0xfe 0x%02x not handled", ip [1]);
9760                         }
9761                         break;
9762                 }
9763                 default:
9764                         g_error ("opcode 0x%02x not handled", *ip);
9765                 }
9766         }
9767         if (start_new_bblock != 1)
9768                 UNVERIFIED;
9769
9770         bblock->cil_length = ip - bblock->cil_code;
9771         bblock->next_bb = end_bblock;
9772
9773         if (cfg->method == method && cfg->domainvar) {
9774                 MonoInst *store;
9775                 MonoInst *get_domain;
9776
9777                 cfg->cbb = init_localsbb;
9778
9779                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
9780                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
9781                 }
9782                 else {
9783                         get_domain->dreg = alloc_preg (cfg);
9784                         MONO_ADD_INS (cfg->cbb, get_domain);
9785                 }               
9786                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
9787                 MONO_ADD_INS (cfg->cbb, store);
9788         }
9789
9790 #ifdef TARGET_POWERPC
9791         if (cfg->compile_aot)
9792                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
9793                 mono_get_got_var (cfg);
9794 #endif
9795
9796         if (cfg->method == method && cfg->got_var)
9797                 mono_emit_load_got_addr (cfg);
9798
9799         if (init_locals) {
9800                 MonoInst *store;
9801
9802                 cfg->cbb = init_localsbb;
9803                 cfg->ip = NULL;
9804                 for (i = 0; i < header->num_locals; ++i) {
9805                         MonoType *ptype = header->locals [i];
9806                         int t = ptype->type;
9807                         dreg = cfg->locals [i]->dreg;
9808
9809                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
9810                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
9811                         if (ptype->byref) {
9812                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9813                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
9814                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
9815                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
9816                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
9817                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
9818                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
9819                                 ins->type = STACK_R8;
9820                                 ins->inst_p0 = (void*)&r8_0;
9821                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
9822                                 MONO_ADD_INS (init_localsbb, ins);
9823                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
9824                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
9825                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
9826                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
9827                         } else {
9828                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
9829                         }
9830                 }
9831         }
9832
9833         cfg->ip = NULL;
9834
9835         if (cfg->method == method) {
9836                 MonoBasicBlock *bb;
9837                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
9838                         bb->region = mono_find_block_region (cfg, bb->real_offset);
9839                         if (cfg->spvars)
9840                                 mono_create_spvar_for_region (cfg, bb->region);
9841                         if (cfg->verbose_level > 2)
9842                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
9843                 }
9844         }
9845
9846         g_slist_free (class_inits);
9847         dont_inline = g_list_remove (dont_inline, method);
9848
9849         if (inline_costs < 0) {
9850                 char *mname;
9851
9852                 /* Method is too large */
9853                 mname = mono_method_full_name (method, TRUE);
9854                 cfg->exception_type = MONO_EXCEPTION_INVALID_PROGRAM;
9855                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
9856                 g_free (mname);
9857                 return -1;
9858         }
9859
9860         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
9861                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
9862
9863         return inline_costs;
9864  
9865  exception_exit:
9866         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
9867         g_slist_free (class_inits);
9868         dont_inline = g_list_remove (dont_inline, method);
9869         return -1;
9870
9871  inline_failure:
9872         g_slist_free (class_inits);
9873         dont_inline = g_list_remove (dont_inline, method);
9874         return -1;
9875
9876  load_error:
9877         g_slist_free (class_inits);
9878         dont_inline = g_list_remove (dont_inline, method);
9879         cfg->exception_type = MONO_EXCEPTION_TYPE_LOAD;
9880         return -1;
9881
9882  unverified:
9883         g_slist_free (class_inits);
9884         dont_inline = g_list_remove (dont_inline, method);
9885         set_exception_type_from_invalid_il (cfg, method, ip);
9886         return -1;
9887 }
9888
9889 static int
9890 store_membase_reg_to_store_membase_imm (int opcode)
9891 {
9892         switch (opcode) {
9893         case OP_STORE_MEMBASE_REG:
9894                 return OP_STORE_MEMBASE_IMM;
9895         case OP_STOREI1_MEMBASE_REG:
9896                 return OP_STOREI1_MEMBASE_IMM;
9897         case OP_STOREI2_MEMBASE_REG:
9898                 return OP_STOREI2_MEMBASE_IMM;
9899         case OP_STOREI4_MEMBASE_REG:
9900                 return OP_STOREI4_MEMBASE_IMM;
9901         case OP_STOREI8_MEMBASE_REG:
9902                 return OP_STOREI8_MEMBASE_IMM;
9903         default:
9904                 g_assert_not_reached ();
9905         }
9906
9907         return -1;
9908 }               
9909
9910 #endif /* DISABLE_JIT */
9911
9912 int
9913 mono_op_to_op_imm (int opcode)
9914 {
9915         switch (opcode) {
9916         case OP_IADD:
9917                 return OP_IADD_IMM;
9918         case OP_ISUB:
9919                 return OP_ISUB_IMM;
9920         case OP_IDIV:
9921                 return OP_IDIV_IMM;
9922         case OP_IDIV_UN:
9923                 return OP_IDIV_UN_IMM;
9924         case OP_IREM:
9925                 return OP_IREM_IMM;
9926         case OP_IREM_UN:
9927                 return OP_IREM_UN_IMM;
9928         case OP_IMUL:
9929                 return OP_IMUL_IMM;
9930         case OP_IAND:
9931                 return OP_IAND_IMM;
9932         case OP_IOR:
9933                 return OP_IOR_IMM;
9934         case OP_IXOR:
9935                 return OP_IXOR_IMM;
9936         case OP_ISHL:
9937                 return OP_ISHL_IMM;
9938         case OP_ISHR:
9939                 return OP_ISHR_IMM;
9940         case OP_ISHR_UN:
9941                 return OP_ISHR_UN_IMM;
9942
9943         case OP_LADD:
9944                 return OP_LADD_IMM;
9945         case OP_LSUB:
9946                 return OP_LSUB_IMM;
9947         case OP_LAND:
9948                 return OP_LAND_IMM;
9949         case OP_LOR:
9950                 return OP_LOR_IMM;
9951         case OP_LXOR:
9952                 return OP_LXOR_IMM;
9953         case OP_LSHL:
9954                 return OP_LSHL_IMM;
9955         case OP_LSHR:
9956                 return OP_LSHR_IMM;
9957         case OP_LSHR_UN:
9958                 return OP_LSHR_UN_IMM;          
9959
9960         case OP_COMPARE:
9961                 return OP_COMPARE_IMM;
9962         case OP_ICOMPARE:
9963                 return OP_ICOMPARE_IMM;
9964         case OP_LCOMPARE:
9965                 return OP_LCOMPARE_IMM;
9966
9967         case OP_STORE_MEMBASE_REG:
9968                 return OP_STORE_MEMBASE_IMM;
9969         case OP_STOREI1_MEMBASE_REG:
9970                 return OP_STOREI1_MEMBASE_IMM;
9971         case OP_STOREI2_MEMBASE_REG:
9972                 return OP_STOREI2_MEMBASE_IMM;
9973         case OP_STOREI4_MEMBASE_REG:
9974                 return OP_STOREI4_MEMBASE_IMM;
9975
9976 #if defined(TARGET_X86) || defined (TARGET_AMD64)
9977         case OP_X86_PUSH:
9978                 return OP_X86_PUSH_IMM;
9979         case OP_X86_COMPARE_MEMBASE_REG:
9980                 return OP_X86_COMPARE_MEMBASE_IMM;
9981 #endif
9982 #if defined(TARGET_AMD64)
9983         case OP_AMD64_ICOMPARE_MEMBASE_REG:
9984                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
9985 #endif
9986         case OP_VOIDCALL_REG:
9987                 return OP_VOIDCALL;
9988         case OP_CALL_REG:
9989                 return OP_CALL;
9990         case OP_LCALL_REG:
9991                 return OP_LCALL;
9992         case OP_FCALL_REG:
9993                 return OP_FCALL;
9994         case OP_LOCALLOC:
9995                 return OP_LOCALLOC_IMM;
9996         }
9997
9998         return -1;
9999 }
10000
10001 static int
10002 ldind_to_load_membase (int opcode)
10003 {
10004         switch (opcode) {
10005         case CEE_LDIND_I1:
10006                 return OP_LOADI1_MEMBASE;
10007         case CEE_LDIND_U1:
10008                 return OP_LOADU1_MEMBASE;
10009         case CEE_LDIND_I2:
10010                 return OP_LOADI2_MEMBASE;
10011         case CEE_LDIND_U2:
10012                 return OP_LOADU2_MEMBASE;
10013         case CEE_LDIND_I4:
10014                 return OP_LOADI4_MEMBASE;
10015         case CEE_LDIND_U4:
10016                 return OP_LOADU4_MEMBASE;
10017         case CEE_LDIND_I:
10018                 return OP_LOAD_MEMBASE;
10019         case CEE_LDIND_REF:
10020                 return OP_LOAD_MEMBASE;
10021         case CEE_LDIND_I8:
10022                 return OP_LOADI8_MEMBASE;
10023         case CEE_LDIND_R4:
10024                 return OP_LOADR4_MEMBASE;
10025         case CEE_LDIND_R8:
10026                 return OP_LOADR8_MEMBASE;
10027         default:
10028                 g_assert_not_reached ();
10029         }
10030
10031         return -1;
10032 }
10033
10034 static int
10035 stind_to_store_membase (int opcode)
10036 {
10037         switch (opcode) {
10038         case CEE_STIND_I1:
10039                 return OP_STOREI1_MEMBASE_REG;
10040         case CEE_STIND_I2:
10041                 return OP_STOREI2_MEMBASE_REG;
10042         case CEE_STIND_I4:
10043                 return OP_STOREI4_MEMBASE_REG;
10044         case CEE_STIND_I:
10045         case CEE_STIND_REF:
10046                 return OP_STORE_MEMBASE_REG;
10047         case CEE_STIND_I8:
10048                 return OP_STOREI8_MEMBASE_REG;
10049         case CEE_STIND_R4:
10050                 return OP_STORER4_MEMBASE_REG;
10051         case CEE_STIND_R8:
10052                 return OP_STORER8_MEMBASE_REG;
10053         default:
10054                 g_assert_not_reached ();
10055         }
10056
10057         return -1;
10058 }
10059
10060 int
10061 mono_load_membase_to_load_mem (int opcode)
10062 {
10063         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
10064 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10065         switch (opcode) {
10066         case OP_LOAD_MEMBASE:
10067                 return OP_LOAD_MEM;
10068         case OP_LOADU1_MEMBASE:
10069                 return OP_LOADU1_MEM;
10070         case OP_LOADU2_MEMBASE:
10071                 return OP_LOADU2_MEM;
10072         case OP_LOADI4_MEMBASE:
10073                 return OP_LOADI4_MEM;
10074         case OP_LOADU4_MEMBASE:
10075                 return OP_LOADU4_MEM;
10076 #if SIZEOF_REGISTER == 8
10077         case OP_LOADI8_MEMBASE:
10078                 return OP_LOADI8_MEM;
10079 #endif
10080         }
10081 #endif
10082
10083         return -1;
10084 }
10085
10086 static inline int
10087 op_to_op_dest_membase (int store_opcode, int opcode)
10088 {
10089 #if defined(TARGET_X86)
10090         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
10091                 return -1;
10092
10093         switch (opcode) {
10094         case OP_IADD:
10095                 return OP_X86_ADD_MEMBASE_REG;
10096         case OP_ISUB:
10097                 return OP_X86_SUB_MEMBASE_REG;
10098         case OP_IAND:
10099                 return OP_X86_AND_MEMBASE_REG;
10100         case OP_IOR:
10101                 return OP_X86_OR_MEMBASE_REG;
10102         case OP_IXOR:
10103                 return OP_X86_XOR_MEMBASE_REG;
10104         case OP_ADD_IMM:
10105         case OP_IADD_IMM:
10106                 return OP_X86_ADD_MEMBASE_IMM;
10107         case OP_SUB_IMM:
10108         case OP_ISUB_IMM:
10109                 return OP_X86_SUB_MEMBASE_IMM;
10110         case OP_AND_IMM:
10111         case OP_IAND_IMM:
10112                 return OP_X86_AND_MEMBASE_IMM;
10113         case OP_OR_IMM:
10114         case OP_IOR_IMM:
10115                 return OP_X86_OR_MEMBASE_IMM;
10116         case OP_XOR_IMM:
10117         case OP_IXOR_IMM:
10118                 return OP_X86_XOR_MEMBASE_IMM;
10119         case OP_MOVE:
10120                 return OP_NOP;
10121         }
10122 #endif
10123
10124 #if defined(TARGET_AMD64)
10125         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
10126                 return -1;
10127
10128         switch (opcode) {
10129         case OP_IADD:
10130                 return OP_X86_ADD_MEMBASE_REG;
10131         case OP_ISUB:
10132                 return OP_X86_SUB_MEMBASE_REG;
10133         case OP_IAND:
10134                 return OP_X86_AND_MEMBASE_REG;
10135         case OP_IOR:
10136                 return OP_X86_OR_MEMBASE_REG;
10137         case OP_IXOR:
10138                 return OP_X86_XOR_MEMBASE_REG;
10139         case OP_IADD_IMM:
10140                 return OP_X86_ADD_MEMBASE_IMM;
10141         case OP_ISUB_IMM:
10142                 return OP_X86_SUB_MEMBASE_IMM;
10143         case OP_IAND_IMM:
10144                 return OP_X86_AND_MEMBASE_IMM;
10145         case OP_IOR_IMM:
10146                 return OP_X86_OR_MEMBASE_IMM;
10147         case OP_IXOR_IMM:
10148                 return OP_X86_XOR_MEMBASE_IMM;
10149         case OP_LADD:
10150                 return OP_AMD64_ADD_MEMBASE_REG;
10151         case OP_LSUB:
10152                 return OP_AMD64_SUB_MEMBASE_REG;
10153         case OP_LAND:
10154                 return OP_AMD64_AND_MEMBASE_REG;
10155         case OP_LOR:
10156                 return OP_AMD64_OR_MEMBASE_REG;
10157         case OP_LXOR:
10158                 return OP_AMD64_XOR_MEMBASE_REG;
10159         case OP_ADD_IMM:
10160         case OP_LADD_IMM:
10161                 return OP_AMD64_ADD_MEMBASE_IMM;
10162         case OP_SUB_IMM:
10163         case OP_LSUB_IMM:
10164                 return OP_AMD64_SUB_MEMBASE_IMM;
10165         case OP_AND_IMM:
10166         case OP_LAND_IMM:
10167                 return OP_AMD64_AND_MEMBASE_IMM;
10168         case OP_OR_IMM:
10169         case OP_LOR_IMM:
10170                 return OP_AMD64_OR_MEMBASE_IMM;
10171         case OP_XOR_IMM:
10172         case OP_LXOR_IMM:
10173                 return OP_AMD64_XOR_MEMBASE_IMM;
10174         case OP_MOVE:
10175                 return OP_NOP;
10176         }
10177 #endif
10178
10179         return -1;
10180 }
10181
10182 static inline int
10183 op_to_op_store_membase (int store_opcode, int opcode)
10184 {
10185 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10186         switch (opcode) {
10187         case OP_ICEQ:
10188                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10189                         return OP_X86_SETEQ_MEMBASE;
10190         case OP_CNE:
10191                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10192                         return OP_X86_SETNE_MEMBASE;
10193         }
10194 #endif
10195
10196         return -1;
10197 }
10198
10199 static inline int
10200 op_to_op_src1_membase (int load_opcode, int opcode)
10201 {
10202 #ifdef TARGET_X86
10203         /* FIXME: This has sign extension issues */
10204         /*
10205         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10206                 return OP_X86_COMPARE_MEMBASE8_IMM;
10207         */
10208
10209         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10210                 return -1;
10211
10212         switch (opcode) {
10213         case OP_X86_PUSH:
10214                 return OP_X86_PUSH_MEMBASE;
10215         case OP_COMPARE_IMM:
10216         case OP_ICOMPARE_IMM:
10217                 return OP_X86_COMPARE_MEMBASE_IMM;
10218         case OP_COMPARE:
10219         case OP_ICOMPARE:
10220                 return OP_X86_COMPARE_MEMBASE_REG;
10221         }
10222 #endif
10223
10224 #ifdef TARGET_AMD64
10225         /* FIXME: This has sign extension issues */
10226         /*
10227         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10228                 return OP_X86_COMPARE_MEMBASE8_IMM;
10229         */
10230
10231         switch (opcode) {
10232         case OP_X86_PUSH:
10233                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10234                         return OP_X86_PUSH_MEMBASE;
10235                 break;
10236                 /* FIXME: This only works for 32 bit immediates
10237         case OP_COMPARE_IMM:
10238         case OP_LCOMPARE_IMM:
10239                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10240                         return OP_AMD64_COMPARE_MEMBASE_IMM;
10241                 */
10242         case OP_ICOMPARE_IMM:
10243                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10244                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10245                 break;
10246         case OP_COMPARE:
10247         case OP_LCOMPARE:
10248                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10249                         return OP_AMD64_COMPARE_MEMBASE_REG;
10250                 break;
10251         case OP_ICOMPARE:
10252                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10253                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
10254                 break;
10255         }
10256 #endif
10257
10258         return -1;
10259 }
10260
10261 static inline int
10262 op_to_op_src2_membase (int load_opcode, int opcode)
10263 {
10264 #ifdef TARGET_X86
10265         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10266                 return -1;
10267         
10268         switch (opcode) {
10269         case OP_COMPARE:
10270         case OP_ICOMPARE:
10271                 return OP_X86_COMPARE_REG_MEMBASE;
10272         case OP_IADD:
10273                 return OP_X86_ADD_REG_MEMBASE;
10274         case OP_ISUB:
10275                 return OP_X86_SUB_REG_MEMBASE;
10276         case OP_IAND:
10277                 return OP_X86_AND_REG_MEMBASE;
10278         case OP_IOR:
10279                 return OP_X86_OR_REG_MEMBASE;
10280         case OP_IXOR:
10281                 return OP_X86_XOR_REG_MEMBASE;
10282         }
10283 #endif
10284
10285 #ifdef TARGET_AMD64
10286         switch (opcode) {
10287         case OP_ICOMPARE:
10288                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10289                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
10290                 break;
10291         case OP_COMPARE:
10292         case OP_LCOMPARE:
10293                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10294                         return OP_AMD64_COMPARE_REG_MEMBASE;
10295                 break;
10296         case OP_IADD:
10297                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10298                         return OP_X86_ADD_REG_MEMBASE;
10299         case OP_ISUB:
10300                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10301                         return OP_X86_SUB_REG_MEMBASE;
10302         case OP_IAND:
10303                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10304                         return OP_X86_AND_REG_MEMBASE;
10305         case OP_IOR:
10306                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10307                         return OP_X86_OR_REG_MEMBASE;
10308         case OP_IXOR:
10309                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10310                         return OP_X86_XOR_REG_MEMBASE;
10311         case OP_LADD:
10312                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10313                         return OP_AMD64_ADD_REG_MEMBASE;
10314         case OP_LSUB:
10315                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10316                         return OP_AMD64_SUB_REG_MEMBASE;
10317         case OP_LAND:
10318                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10319                         return OP_AMD64_AND_REG_MEMBASE;
10320         case OP_LOR:
10321                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10322                         return OP_AMD64_OR_REG_MEMBASE;
10323         case OP_LXOR:
10324                 if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE))
10325                         return OP_AMD64_XOR_REG_MEMBASE;
10326         }
10327 #endif
10328
10329         return -1;
10330 }
10331
10332 int
10333 mono_op_to_op_imm_noemul (int opcode)
10334 {
10335         switch (opcode) {
10336 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
10337         case OP_LSHR:
10338         case OP_LSHL:
10339         case OP_LSHR_UN:
10340 #endif
10341 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10342         case OP_IDIV:
10343         case OP_IDIV_UN:
10344         case OP_IREM:
10345         case OP_IREM_UN:
10346 #endif
10347                 return -1;
10348         default:
10349                 return mono_op_to_op_imm (opcode);
10350         }
10351 }
10352
10353 #ifndef DISABLE_JIT
10354
10355 /**
10356  * mono_handle_global_vregs:
10357  *
10358  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
10359  * for them.
10360  */
10361 void
10362 mono_handle_global_vregs (MonoCompile *cfg)
10363 {
10364         gint32 *vreg_to_bb;
10365         MonoBasicBlock *bb;
10366         int i, pos;
10367
10368         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
10369
10370 #ifdef MONO_ARCH_SIMD_INTRINSICS
10371         if (cfg->uses_simd_intrinsics)
10372                 mono_simd_simplify_indirection (cfg);
10373 #endif
10374
10375         /* Find local vregs used in more than one bb */
10376         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10377                 MonoInst *ins = bb->code;       
10378                 int block_num = bb->block_num;
10379
10380                 if (cfg->verbose_level > 2)
10381                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
10382
10383                 cfg->cbb = bb;
10384                 for (; ins; ins = ins->next) {
10385                         const char *spec = INS_INFO (ins->opcode);
10386                         int regtype = 0, regindex;
10387                         gint32 prev_bb;
10388
10389                         if (G_UNLIKELY (cfg->verbose_level > 2))
10390                                 mono_print_ins (ins);
10391
10392                         g_assert (ins->opcode >= MONO_CEE_LAST);
10393
10394                         for (regindex = 0; regindex < 4; regindex ++) {
10395                                 int vreg = 0;
10396
10397                                 if (regindex == 0) {
10398                                         regtype = spec [MONO_INST_DEST];
10399                                         if (regtype == ' ')
10400                                                 continue;
10401                                         vreg = ins->dreg;
10402                                 } else if (regindex == 1) {
10403                                         regtype = spec [MONO_INST_SRC1];
10404                                         if (regtype == ' ')
10405                                                 continue;
10406                                         vreg = ins->sreg1;
10407                                 } else if (regindex == 2) {
10408                                         regtype = spec [MONO_INST_SRC2];
10409                                         if (regtype == ' ')
10410                                                 continue;
10411                                         vreg = ins->sreg2;
10412                                 } else if (regindex == 3) {
10413                                         regtype = spec [MONO_INST_SRC3];
10414                                         if (regtype == ' ')
10415                                                 continue;
10416                                         vreg = ins->sreg3;
10417                                 }
10418
10419 #if SIZEOF_REGISTER == 4
10420                                 /* In the LLVM case, the long opcodes are not decomposed */
10421                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
10422                                         /*
10423                                          * Since some instructions reference the original long vreg,
10424                                          * and some reference the two component vregs, it is quite hard
10425                                          * to determine when it needs to be global. So be conservative.
10426                                          */
10427                                         if (!get_vreg_to_inst (cfg, vreg)) {
10428                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
10429
10430                                                 if (cfg->verbose_level > 2)
10431                                                         printf ("LONG VREG R%d made global.\n", vreg);
10432                                         }
10433
10434                                         /*
10435                                          * Make the component vregs volatile since the optimizations can
10436                                          * get confused otherwise.
10437                                          */
10438                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
10439                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
10440                                 }
10441 #endif
10442
10443                                 g_assert (vreg != -1);
10444
10445                                 prev_bb = vreg_to_bb [vreg];
10446                                 if (prev_bb == 0) {
10447                                         /* 0 is a valid block num */
10448                                         vreg_to_bb [vreg] = block_num + 1;
10449                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
10450                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
10451                                                 continue;
10452
10453                                         if (!get_vreg_to_inst (cfg, vreg)) {
10454                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10455                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
10456
10457                                                 switch (regtype) {
10458                                                 case 'i':
10459                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
10460                                                         break;
10461                                                 case 'f':
10462                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
10463                                                         break;
10464                                                 case 'v':
10465                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
10466                                                         break;
10467                                                 default:
10468                                                         g_assert_not_reached ();
10469                                                 }
10470                                         }
10471
10472                                         /* Flag as having been used in more than one bb */
10473                                         vreg_to_bb [vreg] = -1;
10474                                 }
10475                         }
10476                 }
10477         }
10478
10479         /* If a variable is used in only one bblock, convert it into a local vreg */
10480         for (i = 0; i < cfg->num_varinfo; i++) {
10481                 MonoInst *var = cfg->varinfo [i];
10482                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
10483
10484                 switch (var->type) {
10485                 case STACK_I4:
10486                 case STACK_OBJ:
10487                 case STACK_PTR:
10488                 case STACK_MP:
10489                 case STACK_VTYPE:
10490 #if SIZEOF_REGISTER == 8
10491                 case STACK_I8:
10492 #endif
10493 #if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
10494                 /* Enabling this screws up the fp stack on x86 */
10495                 case STACK_R8:
10496 #endif
10497                         /* Arguments are implicitly global */
10498                         /* Putting R4 vars into registers doesn't work currently */
10499                         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) {
10500                                 /* 
10501                                  * Make that the variable's liveness interval doesn't contain a call, since
10502                                  * that would cause the lvreg to be spilled, making the whole optimization
10503                                  * useless.
10504                                  */
10505                                 /* This is too slow for JIT compilation */
10506 #if 0
10507                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
10508                                         MonoInst *ins;
10509                                         int def_index, call_index, ins_index;
10510                                         gboolean spilled = FALSE;
10511
10512                                         def_index = -1;
10513                                         call_index = -1;
10514                                         ins_index = 0;
10515                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
10516                                                 const char *spec = INS_INFO (ins->opcode);
10517
10518                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
10519                                                         def_index = ins_index;
10520
10521                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
10522                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
10523                                                         if (call_index > def_index) {
10524                                                                 spilled = TRUE;
10525                                                                 break;
10526                                                         }
10527                                                 }
10528
10529                                                 if (MONO_IS_CALL (ins))
10530                                                         call_index = ins_index;
10531
10532                                                 ins_index ++;
10533                                         }
10534
10535                                         if (spilled)
10536                                                 break;
10537                                 }
10538 #endif
10539
10540                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10541                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
10542                                 var->flags |= MONO_INST_IS_DEAD;
10543                                 cfg->vreg_to_inst [var->dreg] = NULL;
10544                         }
10545                         break;
10546                 }
10547         }
10548
10549         /* 
10550          * Compress the varinfo and vars tables so the liveness computation is faster and
10551          * takes up less space.
10552          */
10553         pos = 0;
10554         for (i = 0; i < cfg->num_varinfo; ++i) {
10555                 MonoInst *var = cfg->varinfo [i];
10556                 if (pos < i && cfg->locals_start == i)
10557                         cfg->locals_start = pos;
10558                 if (!(var->flags & MONO_INST_IS_DEAD)) {
10559                         if (pos < i) {
10560                                 cfg->varinfo [pos] = cfg->varinfo [i];
10561                                 cfg->varinfo [pos]->inst_c0 = pos;
10562                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
10563                                 cfg->vars [pos].idx = pos;
10564 #if SIZEOF_REGISTER == 4
10565                                 if (cfg->varinfo [pos]->type == STACK_I8) {
10566                                         /* Modify the two component vars too */
10567                                         MonoInst *var1;
10568
10569                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
10570                                         var1->inst_c0 = pos;
10571                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
10572                                         var1->inst_c0 = pos;
10573                                 }
10574 #endif
10575                         }
10576                         pos ++;
10577                 }
10578         }
10579         cfg->num_varinfo = pos;
10580         if (cfg->locals_start > cfg->num_varinfo)
10581                 cfg->locals_start = cfg->num_varinfo;
10582 }
10583
10584 /**
10585  * mono_spill_global_vars:
10586  *
10587  *   Generate spill code for variables which are not allocated to registers, 
10588  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
10589  * code is generated which could be optimized by the local optimization passes.
10590  */
10591 void
10592 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
10593 {
10594         MonoBasicBlock *bb;
10595         char spec2 [16];
10596         int orig_next_vreg;
10597         guint32 *vreg_to_lvreg;
10598         guint32 *lvregs;
10599         guint32 i, lvregs_len;
10600         gboolean dest_has_lvreg = FALSE;
10601         guint32 stacktypes [128];
10602         MonoInst **live_range_start, **live_range_end;
10603         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
10604
10605         *need_local_opts = FALSE;
10606
10607         memset (spec2, 0, sizeof (spec2));
10608
10609         /* FIXME: Move this function to mini.c */
10610         stacktypes ['i'] = STACK_PTR;
10611         stacktypes ['l'] = STACK_I8;
10612         stacktypes ['f'] = STACK_R8;
10613 #ifdef MONO_ARCH_SIMD_INTRINSICS
10614         stacktypes ['x'] = STACK_VTYPE;
10615 #endif
10616
10617 #if SIZEOF_REGISTER == 4
10618         /* Create MonoInsts for longs */
10619         for (i = 0; i < cfg->num_varinfo; i++) {
10620                 MonoInst *ins = cfg->varinfo [i];
10621
10622                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
10623                         switch (ins->type) {
10624 #ifdef MONO_ARCH_SOFT_FLOAT
10625                         case STACK_R8:
10626 #endif
10627                         case STACK_I8: {
10628                                 MonoInst *tree;
10629
10630                                 g_assert (ins->opcode == OP_REGOFFSET);
10631
10632                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
10633                                 g_assert (tree);
10634                                 tree->opcode = OP_REGOFFSET;
10635                                 tree->inst_basereg = ins->inst_basereg;
10636                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
10637
10638                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
10639                                 g_assert (tree);
10640                                 tree->opcode = OP_REGOFFSET;
10641                                 tree->inst_basereg = ins->inst_basereg;
10642                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
10643                                 break;
10644                         }
10645                         default:
10646                                 break;
10647                         }
10648                 }
10649         }
10650 #endif
10651
10652         /* FIXME: widening and truncation */
10653
10654         /*
10655          * As an optimization, when a variable allocated to the stack is first loaded into 
10656          * an lvreg, we will remember the lvreg and use it the next time instead of loading
10657          * the variable again.
10658          */
10659         orig_next_vreg = cfg->next_vreg;
10660         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
10661         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
10662         lvregs_len = 0;
10663
10664         /* 
10665          * These arrays contain the first and last instructions accessing a given
10666          * variable.
10667          * Since we emit bblocks in the same order we process them here, and we
10668          * don't split live ranges, these will precisely describe the live range of
10669          * the variable, i.e. the instruction range where a valid value can be found
10670          * in the variables location.
10671          */
10672         /* FIXME: Only do this if debugging info is requested */
10673         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
10674         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
10675         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
10676         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
10677         
10678         /* Add spill loads/stores */
10679         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10680                 MonoInst *ins;
10681
10682                 if (cfg->verbose_level > 2)
10683                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
10684
10685                 /* Clear vreg_to_lvreg array */
10686                 for (i = 0; i < lvregs_len; i++)
10687                         vreg_to_lvreg [lvregs [i]] = 0;
10688                 lvregs_len = 0;
10689
10690                 cfg->cbb = bb;
10691                 MONO_BB_FOR_EACH_INS (bb, ins) {
10692                         const char *spec = INS_INFO (ins->opcode);
10693                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
10694                         gboolean store, no_lvreg;
10695                         int sregs [MONO_MAX_SRC_REGS];
10696
10697                         if (G_UNLIKELY (cfg->verbose_level > 2))
10698                                 mono_print_ins (ins);
10699
10700                         if (ins->opcode == OP_NOP)
10701                                 continue;
10702
10703                         /* 
10704                          * We handle LDADDR here as well, since it can only be decomposed
10705                          * when variable addresses are known.
10706                          */
10707                         if (ins->opcode == OP_LDADDR) {
10708                                 MonoInst *var = ins->inst_p0;
10709
10710                                 if (var->opcode == OP_VTARG_ADDR) {
10711                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
10712                                         MonoInst *vtaddr = var->inst_left;
10713                                         if (vtaddr->opcode == OP_REGVAR) {
10714                                                 ins->opcode = OP_MOVE;
10715                                                 ins->sreg1 = vtaddr->dreg;
10716                                         }
10717                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
10718                                                 ins->opcode = OP_LOAD_MEMBASE;
10719                                                 ins->inst_basereg = vtaddr->inst_basereg;
10720                                                 ins->inst_offset = vtaddr->inst_offset;
10721                                         } else
10722                                                 NOT_IMPLEMENTED;
10723                                 } else {
10724                                         g_assert (var->opcode == OP_REGOFFSET);
10725
10726                                         ins->opcode = OP_ADD_IMM;
10727                                         ins->sreg1 = var->inst_basereg;
10728                                         ins->inst_imm = var->inst_offset;
10729                                 }
10730
10731                                 *need_local_opts = TRUE;
10732                                 spec = INS_INFO (ins->opcode);
10733                         }
10734
10735                         if (ins->opcode < MONO_CEE_LAST) {
10736                                 mono_print_ins (ins);
10737                                 g_assert_not_reached ();
10738                         }
10739
10740                         /*
10741                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
10742                          * src register.
10743                          * FIXME:
10744                          */
10745                         if (MONO_IS_STORE_MEMBASE (ins)) {
10746                                 tmp_reg = ins->dreg;
10747                                 ins->dreg = ins->sreg2;
10748                                 ins->sreg2 = tmp_reg;
10749                                 store = TRUE;
10750
10751                                 spec2 [MONO_INST_DEST] = ' ';
10752                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10753                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10754                                 spec2 [MONO_INST_SRC3] = ' ';
10755                                 spec = spec2;
10756                         } else if (MONO_IS_STORE_MEMINDEX (ins))
10757                                 g_assert_not_reached ();
10758                         else
10759                                 store = FALSE;
10760                         no_lvreg = FALSE;
10761
10762                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
10763                                 printf ("\t %.3s %d", spec, ins->dreg);
10764                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
10765                                 for (srcindex = 0; srcindex < 3; ++srcindex)
10766                                         printf (" %d", sregs [srcindex]);
10767                                 printf ("\n");
10768                         }
10769
10770                         /***************/
10771                         /*    DREG     */
10772                         /***************/
10773                         regtype = spec [MONO_INST_DEST];
10774                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
10775                         prev_dreg = -1;
10776
10777                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
10778                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
10779                                 MonoInst *store_ins;
10780                                 int store_opcode;
10781                                 MonoInst *def_ins = ins;
10782                                 int dreg = ins->dreg; /* The original vreg */
10783
10784                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
10785
10786                                 if (var->opcode == OP_REGVAR) {
10787                                         ins->dreg = var->dreg;
10788                                 } 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)) {
10789                                         /* 
10790                                          * Instead of emitting a load+store, use a _membase opcode.
10791                                          */
10792                                         g_assert (var->opcode == OP_REGOFFSET);
10793                                         if (ins->opcode == OP_MOVE) {
10794                                                 NULLIFY_INS (ins);
10795                                                 def_ins = NULL;
10796                                         } else {
10797                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
10798                                                 ins->inst_basereg = var->inst_basereg;
10799                                                 ins->inst_offset = var->inst_offset;
10800                                                 ins->dreg = -1;
10801                                         }
10802                                         spec = INS_INFO (ins->opcode);
10803                                 } else {
10804                                         guint32 lvreg;
10805
10806                                         g_assert (var->opcode == OP_REGOFFSET);
10807
10808                                         prev_dreg = ins->dreg;
10809
10810                                         /* Invalidate any previous lvreg for this vreg */
10811                                         vreg_to_lvreg [ins->dreg] = 0;
10812
10813                                         lvreg = 0;
10814
10815 #ifdef MONO_ARCH_SOFT_FLOAT
10816                                         if (store_opcode == OP_STORER8_MEMBASE_REG) {
10817                                                 regtype = 'l';
10818                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
10819                                         }
10820 #endif
10821
10822                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
10823
10824                                         if (regtype == 'l') {
10825                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
10826                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10827                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
10828                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
10829                                                 def_ins = store_ins;
10830                                         }
10831                                         else {
10832                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
10833
10834                                                 /* Try to fuse the store into the instruction itself */
10835                                                 /* FIXME: Add more instructions */
10836                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
10837                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
10838                                                         ins->inst_imm = ins->inst_c0;
10839                                                         ins->inst_destbasereg = var->inst_basereg;
10840                                                         ins->inst_offset = var->inst_offset;
10841                                                         spec = INS_INFO (ins->opcode);
10842                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
10843                                                         ins->opcode = store_opcode;
10844                                                         ins->inst_destbasereg = var->inst_basereg;
10845                                                         ins->inst_offset = var->inst_offset;
10846
10847                                                         no_lvreg = TRUE;
10848
10849                                                         tmp_reg = ins->dreg;
10850                                                         ins->dreg = ins->sreg2;
10851                                                         ins->sreg2 = tmp_reg;
10852                                                         store = TRUE;
10853
10854                                                         spec2 [MONO_INST_DEST] = ' ';
10855                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
10856                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
10857                                                         spec2 [MONO_INST_SRC3] = ' ';
10858                                                         spec = spec2;
10859                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
10860                                                         // FIXME: The backends expect the base reg to be in inst_basereg
10861                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
10862                                                         ins->dreg = -1;
10863                                                         ins->inst_basereg = var->inst_basereg;
10864                                                         ins->inst_offset = var->inst_offset;
10865                                                         spec = INS_INFO (ins->opcode);
10866                                                 } else {
10867                                                         /* printf ("INS: "); mono_print_ins (ins); */
10868                                                         /* Create a store instruction */
10869                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
10870
10871                                                         /* Insert it after the instruction */
10872                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
10873
10874                                                         def_ins = store_ins;
10875
10876                                                         /* 
10877                                                          * We can't assign ins->dreg to var->dreg here, since the
10878                                                          * sregs could use it. So set a flag, and do it after
10879                                                          * the sregs.
10880                                                          */
10881                                                         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)))
10882                                                                 dest_has_lvreg = TRUE;
10883                                                 }
10884                                         }
10885                                 }
10886
10887                                 if (def_ins && !live_range_start [dreg]) {
10888                                         live_range_start [dreg] = def_ins;
10889                                         live_range_start_bb [dreg] = bb;
10890                                 }
10891                         }
10892
10893                         /************/
10894                         /*  SREGS   */
10895                         /************/
10896                         num_sregs = mono_inst_get_src_registers (ins, sregs);
10897                         for (srcindex = 0; srcindex < 3; ++srcindex) {
10898                                 regtype = spec [MONO_INST_SRC1 + srcindex];
10899                                 sreg = sregs [srcindex];
10900
10901                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
10902                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
10903                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
10904                                         MonoInst *use_ins = ins;
10905                                         MonoInst *load_ins;
10906                                         guint32 load_opcode;
10907
10908                                         if (var->opcode == OP_REGVAR) {
10909                                                 sregs [srcindex] = var->dreg;
10910                                                 //mono_inst_set_src_registers (ins, sregs);
10911                                                 live_range_end [sreg] = use_ins;
10912                                                 live_range_end_bb [sreg] = bb;
10913                                                 continue;
10914                                         }
10915
10916                                         g_assert (var->opcode == OP_REGOFFSET);
10917                                                 
10918                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
10919
10920                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
10921
10922                                         if (vreg_to_lvreg [sreg]) {
10923                                                 g_assert (vreg_to_lvreg [sreg] != -1);
10924
10925                                                 /* The variable is already loaded to an lvreg */
10926                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10927                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
10928                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
10929                                                 //mono_inst_set_src_registers (ins, sregs);
10930                                                 continue;
10931                                         }
10932
10933                                         /* Try to fuse the load into the instruction */
10934                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
10935                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
10936                                                 sregs [0] = var->inst_basereg;
10937                                                 //mono_inst_set_src_registers (ins, sregs);
10938                                                 ins->inst_offset = var->inst_offset;
10939                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
10940                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
10941                                                 sregs [1] = var->inst_basereg;
10942                                                 //mono_inst_set_src_registers (ins, sregs);
10943                                                 ins->inst_offset = var->inst_offset;
10944                                         } else {
10945                                                 if (MONO_IS_REAL_MOVE (ins)) {
10946                                                         ins->opcode = OP_NOP;
10947                                                         sreg = ins->dreg;
10948                                                 } else {
10949                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
10950
10951                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
10952
10953                                                         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) {
10954                                                                 if (var->dreg == prev_dreg) {
10955                                                                         /*
10956                                                                          * sreg refers to the value loaded by the load
10957                                                                          * emitted below, but we need to use ins->dreg
10958                                                                          * since it refers to the store emitted earlier.
10959                                                                          */
10960                                                                         sreg = ins->dreg;
10961                                                                 }
10962                                                                 g_assert (sreg != -1);
10963                                                                 vreg_to_lvreg [var->dreg] = sreg;
10964                                                                 g_assert (lvregs_len < 1024);
10965                                                                 lvregs [lvregs_len ++] = var->dreg;
10966                                                         }
10967                                                 }
10968
10969                                                 sregs [srcindex] = sreg;
10970                                                 //mono_inst_set_src_registers (ins, sregs);
10971
10972                                                 if (regtype == 'l') {
10973                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
10974                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10975                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
10976                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10977                                                         use_ins = load_ins;
10978                                                 }
10979                                                 else {
10980 #if SIZEOF_REGISTER == 4
10981                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
10982 #endif
10983                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
10984                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
10985                                                         use_ins = load_ins;
10986                                                 }
10987                                         }
10988
10989                                         if (var->dreg < orig_next_vreg) {
10990                                                 live_range_end [var->dreg] = use_ins;
10991                                                 live_range_end_bb [var->dreg] = bb;
10992                                         }
10993                                 }
10994                         }
10995                         mono_inst_set_src_registers (ins, sregs);
10996
10997                         if (dest_has_lvreg) {
10998                                 g_assert (ins->dreg != -1);
10999                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
11000                                 g_assert (lvregs_len < 1024);
11001                                 lvregs [lvregs_len ++] = prev_dreg;
11002                                 dest_has_lvreg = FALSE;
11003                         }
11004
11005                         if (store) {
11006                                 tmp_reg = ins->dreg;
11007                                 ins->dreg = ins->sreg2;
11008                                 ins->sreg2 = tmp_reg;
11009                         }
11010
11011                         if (MONO_IS_CALL (ins)) {
11012                                 /* Clear vreg_to_lvreg array */
11013                                 for (i = 0; i < lvregs_len; i++)
11014                                         vreg_to_lvreg [lvregs [i]] = 0;
11015                                 lvregs_len = 0;
11016                         } else if (ins->opcode == OP_NOP) {
11017                                 ins->dreg = -1;
11018                                 MONO_INST_NULLIFY_SREGS (ins);
11019                         }
11020
11021                         if (cfg->verbose_level > 2)
11022                                 mono_print_ins_index (1, ins);
11023                 }
11024         }
11025         
11026 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
11027         /*
11028          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
11029          * by storing the current native offset into MonoMethodVar->live_range_start/end.
11030          */
11031         for (i = 0; i < cfg->num_varinfo; ++i) {
11032                 int vreg = MONO_VARINFO (cfg, i)->vreg;
11033                 MonoInst *ins;
11034
11035                 if (live_range_start [vreg]) {
11036                         MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
11037                         ins->inst_c0 = i;
11038                         ins->inst_c1 = vreg;
11039                         mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
11040                 }
11041                 if (live_range_end [vreg]) {
11042                         MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
11043                         ins->inst_c0 = i;
11044                         ins->inst_c1 = vreg;
11045                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
11046                 }
11047         }
11048 #endif
11049
11050         g_free (live_range_start);
11051         g_free (live_range_end);
11052         g_free (live_range_start_bb);
11053         g_free (live_range_end_bb);
11054 }
11055
11056 /**
11057  * FIXME:
11058  * - use 'iadd' instead of 'int_add'
11059  * - handling ovf opcodes: decompose in method_to_ir.
11060  * - unify iregs/fregs
11061  *   -> partly done, the missing parts are:
11062  *   - a more complete unification would involve unifying the hregs as well, so
11063  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
11064  *     would no longer map to the machine hregs, so the code generators would need to
11065  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
11066  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
11067  *     fp/non-fp branches speeds it up by about 15%.
11068  * - use sext/zext opcodes instead of shifts
11069  * - add OP_ICALL
11070  * - get rid of TEMPLOADs if possible and use vregs instead
11071  * - clean up usage of OP_P/OP_ opcodes
11072  * - cleanup usage of DUMMY_USE
11073  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
11074  *   stack
11075  * - set the stack type and allocate a dreg in the EMIT_NEW macros
11076  * - get rid of all the <foo>2 stuff when the new JIT is ready.
11077  * - make sure handle_stack_args () is called before the branch is emitted
11078  * - when the new IR is done, get rid of all unused stuff
11079  * - COMPARE/BEQ as separate instructions or unify them ?
11080  *   - keeping them separate allows specialized compare instructions like
11081  *     compare_imm, compare_membase
11082  *   - most back ends unify fp compare+branch, fp compare+ceq
11083  * - integrate mono_save_args into inline_method
11084  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
11085  * - handle long shift opts on 32 bit platforms somehow: they require 
11086  *   3 sregs (2 for arg1 and 1 for arg2)
11087  * - make byref a 'normal' type.
11088  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
11089  *   variable if needed.
11090  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
11091  *   like inline_method.
11092  * - remove inlining restrictions
11093  * - fix LNEG and enable cfold of INEG
11094  * - generalize x86 optimizations like ldelema as a peephole optimization
11095  * - add store_mem_imm for amd64
11096  * - optimize the loading of the interruption flag in the managed->native wrappers
11097  * - avoid special handling of OP_NOP in passes
11098  * - move code inserting instructions into one function/macro.
11099  * - try a coalescing phase after liveness analysis
11100  * - add float -> vreg conversion + local optimizations on !x86
11101  * - figure out how to handle decomposed branches during optimizations, ie.
11102  *   compare+branch, op_jump_table+op_br etc.
11103  * - promote RuntimeXHandles to vregs
11104  * - vtype cleanups:
11105  *   - add a NEW_VARLOADA_VREG macro
11106  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
11107  *   accessing vtype fields.
11108  * - get rid of I8CONST on 64 bit platforms
11109  * - dealing with the increase in code size due to branches created during opcode
11110  *   decomposition:
11111  *   - use extended basic blocks
11112  *     - all parts of the JIT
11113  *     - handle_global_vregs () && local regalloc
11114  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
11115  * - sources of increase in code size:
11116  *   - vtypes
11117  *   - long compares
11118  *   - isinst and castclass
11119  *   - lvregs not allocated to global registers even if used multiple times
11120  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
11121  *   meaningful.
11122  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
11123  * - add all micro optimizations from the old JIT
11124  * - put tree optimizations into the deadce pass
11125  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
11126  *   specific function.
11127  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
11128  *   fcompare + branchCC.
11129  * - create a helper function for allocating a stack slot, taking into account 
11130  *   MONO_CFG_HAS_SPILLUP.
11131  * - merge r68207.
11132  * - merge the ia64 switch changes.
11133  * - optimize mono_regstate2_alloc_int/float.
11134  * - fix the pessimistic handling of variables accessed in exception handler blocks.
11135  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
11136  *   parts of the tree could be separated by other instructions, killing the tree
11137  *   arguments, or stores killing loads etc. Also, should we fold loads into other
11138  *   instructions if the result of the load is used multiple times ?
11139  * - make the REM_IMM optimization in mini-x86.c arch-independent.
11140  * - LAST MERGE: 108395.
11141  * - when returning vtypes in registers, generate IR and append it to the end of the
11142  *   last bb instead of doing it in the epilog.
11143  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
11144  */
11145
11146 /*
11147
11148 NOTES
11149 -----
11150
11151 - When to decompose opcodes:
11152   - earlier: this makes some optimizations hard to implement, since the low level IR
11153   no longer contains the neccessary information. But it is easier to do.
11154   - later: harder to implement, enables more optimizations.
11155 - Branches inside bblocks:
11156   - created when decomposing complex opcodes. 
11157     - branches to another bblock: harmless, but not tracked by the branch 
11158       optimizations, so need to branch to a label at the start of the bblock.
11159     - branches to inside the same bblock: very problematic, trips up the local
11160       reg allocator. Can be fixed by spitting the current bblock, but that is a
11161       complex operation, since some local vregs can become global vregs etc.
11162 - Local/global vregs:
11163   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
11164     local register allocator.
11165   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
11166     structure, created by mono_create_var (). Assigned to hregs or the stack by
11167     the global register allocator.
11168 - When to do optimizations like alu->alu_imm:
11169   - earlier -> saves work later on since the IR will be smaller/simpler
11170   - later -> can work on more instructions
11171 - Handling of valuetypes:
11172   - When a vtype is pushed on the stack, a new temporary is created, an 
11173     instruction computing its address (LDADDR) is emitted and pushed on
11174     the stack. Need to optimize cases when the vtype is used immediately as in
11175     argument passing, stloc etc.
11176 - Instead of the to_end stuff in the old JIT, simply call the function handling
11177   the values on the stack before emitting the last instruction of the bb.
11178 */
11179
11180 #endif /* DISABLE_JIT */