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