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