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