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