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