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