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