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