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