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