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