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