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