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