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