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