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