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