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