[runtime] Fix warnings.
[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  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/gc-internal.h>
53 #include <mono/metadata/security-manager.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/metadata/monitor.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_class_init_trampoline;
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
152 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
155 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
156 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
157
158 /*
159  * Instruction metadata
160  */
161 #ifdef MINI_OP
162 #undef MINI_OP
163 #endif
164 #ifdef MINI_OP3
165 #undef MINI_OP3
166 #endif
167 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
168 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
169 #define NONE ' '
170 #define IREG 'i'
171 #define FREG 'f'
172 #define VREG 'v'
173 #define XREG 'x'
174 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
175 #define LREG IREG
176 #else
177 #define LREG 'l'
178 #endif
179 /* keep in sync with the enum in mini.h */
180 const char
181 ins_info[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
188 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
189 /* 
190  * This should contain the index of the last sreg + 1. This is not the same
191  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
192  */
193 const gint8 ins_sreg_counts[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MONO_INIT_VARINFO(vi,id) do { \
200         (vi)->range.first_use.pos.bid = 0xffff; \
201         (vi)->reg = -1; \
202         (vi)->idx = (id); \
203 } while (0)
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_get_underlying_type (cfg, type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return mono_type_to_regmove (cfg, mini_get_underlying_type (cfg, type));
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
369 }
370
371 static MONO_NEVER_INLINE void
372 break_on_unverified (void)
373 {
374         if (mini_get_debug_options ()->break_on_unverified)
375                 G_BREAKPOINT ();
376 }
377
378 static MONO_NEVER_INLINE void
379 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
380 {
381         char *method_fname = mono_method_full_name (method, TRUE);
382         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
383         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
384         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
385         g_free (method_fname);
386         g_free (cil_method_fname);
387 }
388
389 static MONO_NEVER_INLINE void
390 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
391 {
392         char *method_fname = mono_method_full_name (method, TRUE);
393         char *field_fname = mono_field_full_name (field);
394         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
395         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
396         g_free (method_fname);
397         g_free (field_fname);
398 }
399
400 static MONO_NEVER_INLINE void
401 inline_failure (MonoCompile *cfg, const char *msg)
402 {
403         if (cfg->verbose_level >= 2)
404                 printf ("inline failed: %s\n", msg);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         if (cfg->verbose_level > 2)                                                                                     \
412                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
413         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
414 }
415
416 static MONO_NEVER_INLINE void
417 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
418 {
419         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
420         if (cfg->verbose_level >= 2)
421                 printf ("%s\n", cfg->exception_message);
422         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
423 }
424
425 /*
426  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
427  * foo<T> (int i) { ldarg.0; box T; }
428  */
429 #define UNVERIFIED do { \
430         if (cfg->gsharedvt) { \
431                 if (cfg->verbose_level > 2)                                                                     \
432                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
433                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
434                 goto exception_exit;                                                                                    \
435         }                                                                                                                                       \
436         break_on_unverified ();                                                                                         \
437         goto unverified;                                                                                                        \
438 } while (0)
439
440 #define GET_BBLOCK(cfg,tblock,ip) do {  \
441                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
442                 if (!(tblock)) {        \
443                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
444             NEW_BBLOCK (cfg, (tblock)); \
445                         (tblock)->cil_code = (ip);      \
446                         ADD_BBLOCK (cfg, (tblock));     \
447                 } \
448         } while (0)
449
450 #if defined(TARGET_X86) || defined(TARGET_AMD64)
451 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
452                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
453                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
454                 (dest)->sreg1 = (sr1); \
455                 (dest)->sreg2 = (sr2); \
456                 (dest)->inst_imm = (imm); \
457                 (dest)->backend.shift_amount = (shift); \
458                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
459         } while (0)
460 #endif
461
462 /* Emit conversions so both operands of a binary opcode are of the same type */
463 static void
464 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
465 {
466         MonoInst *arg1 = *arg1_ref;
467         MonoInst *arg2 = *arg2_ref;
468
469         if (cfg->r4fp &&
470                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
471                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
472                 MonoInst *conv;
473
474                 /* Mixing r4/r8 is allowed by the spec */
475                 if (arg1->type == STACK_R4) {
476                         int dreg = alloc_freg (cfg);
477
478                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
479                         conv->type = STACK_R8;
480                         ins->sreg1 = dreg;
481                         *arg1_ref = conv;
482                 }
483                 if (arg2->type == STACK_R4) {
484                         int dreg = alloc_freg (cfg);
485
486                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
487                         conv->type = STACK_R8;
488                         ins->sreg2 = dreg;
489                         *arg2_ref = conv;
490                 }
491         }
492
493 #if SIZEOF_REGISTER == 8
494         /* FIXME: Need to add many more cases */
495         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
496                 MonoInst *widen;
497
498                 int dr = alloc_preg (cfg);
499                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
500                 (ins)->sreg2 = widen->dreg;
501         }
502 #endif
503 }
504
505 #define ADD_BINOP(op) do {      \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp -= 2;        \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 ins->sreg2 = sp [1]->dreg;      \
510                 type_from_op (cfg, ins, sp [0], sp [1]);        \
511                 CHECK_TYPE (ins);       \
512                 /* Have to insert a widening op */               \
513         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
514         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
515         MONO_ADD_INS ((cfg)->cbb, (ins)); \
516         *sp++ = mono_decompose_opcode ((cfg), (ins), &bblock);  \
517         } while (0)
518
519 #define ADD_UNOP(op) do {       \
520                 MONO_INST_NEW (cfg, ins, (op)); \
521                 sp--;   \
522                 ins->sreg1 = sp [0]->dreg;      \
523                 type_from_op (cfg, ins, sp [0], NULL);  \
524                 CHECK_TYPE (ins);       \
525         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
526         MONO_ADD_INS ((cfg)->cbb, (ins)); \
527                 *sp++ = mono_decompose_opcode (cfg, ins, &bblock);      \
528         } while (0)
529
530 #define ADD_BINCOND(next_block) do {    \
531                 MonoInst *cmp;  \
532                 sp -= 2; \
533                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
534                 cmp->sreg1 = sp [0]->dreg;      \
535                 cmp->sreg2 = sp [1]->dreg;      \
536                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
537                 CHECK_TYPE (cmp);       \
538                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
539                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
540                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
541                 GET_BBLOCK (cfg, tblock, target);               \
542                 link_bblock (cfg, bblock, tblock);      \
543                 ins->inst_true_bb = tblock;     \
544                 if ((next_block)) {     \
545                         link_bblock (cfg, bblock, (next_block));        \
546                         ins->inst_false_bb = (next_block);      \
547                         start_new_bblock = 1;   \
548                 } else {        \
549                         GET_BBLOCK (cfg, tblock, ip);           \
550                         link_bblock (cfg, bblock, tblock);      \
551                         ins->inst_false_bb = tblock;    \
552                         start_new_bblock = 2;   \
553                 }       \
554                 if (sp != stack_start) {                                                                        \
555                     handle_stack_args (cfg, stack_start, sp - stack_start); \
556                         CHECK_UNVERIFIABLE (cfg); \
557                 } \
558         MONO_ADD_INS (bblock, cmp); \
559                 MONO_ADD_INS (bblock, ins);     \
560         } while (0)
561
562 /* *
563  * link_bblock: Links two basic blocks
564  *
565  * links two basic blocks in the control flow graph, the 'from'
566  * argument is the starting block and the 'to' argument is the block
567  * the control flow ends to after 'from'.
568  */
569 static void
570 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
571 {
572         MonoBasicBlock **newa;
573         int i, found;
574
575 #if 0
576         if (from->cil_code) {
577                 if (to->cil_code)
578                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
581         } else {
582                 if (to->cil_code)
583                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
584                 else
585                         printf ("edge from entry to exit\n");
586         }
587 #endif
588
589         found = FALSE;
590         for (i = 0; i < from->out_count; ++i) {
591                 if (to == from->out_bb [i]) {
592                         found = TRUE;
593                         break;
594                 }
595         }
596         if (!found) {
597                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
598                 for (i = 0; i < from->out_count; ++i) {
599                         newa [i] = from->out_bb [i];
600                 }
601                 newa [i] = to;
602                 from->out_count++;
603                 from->out_bb = newa;
604         }
605
606         found = FALSE;
607         for (i = 0; i < to->in_count; ++i) {
608                 if (from == to->in_bb [i]) {
609                         found = TRUE;
610                         break;
611                 }
612         }
613         if (!found) {
614                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
615                 for (i = 0; i < to->in_count; ++i) {
616                         newa [i] = to->in_bb [i];
617                 }
618                 newa [i] = from;
619                 to->in_count++;
620                 to->in_bb = newa;
621         }
622 }
623
624 void
625 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
626 {
627         link_bblock (cfg, from, to);
628 }
629
630 /**
631  * mono_find_block_region:
632  *
633  *   We mark each basic block with a region ID. We use that to avoid BB
634  *   optimizations when blocks are in different regions.
635  *
636  * Returns:
637  *   A region token that encodes where this region is, and information
638  *   about the clause owner for this block.
639  *
640  *   The region encodes the try/catch/filter clause that owns this block
641  *   as well as the type.  -1 is a special value that represents a block
642  *   that is in none of try/catch/filter.
643  */
644 static int
645 mono_find_block_region (MonoCompile *cfg, int offset)
646 {
647         MonoMethodHeader *header = cfg->header;
648         MonoExceptionClause *clause;
649         int i;
650
651         for (i = 0; i < header->num_clauses; ++i) {
652                 clause = &header->clauses [i];
653                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
654                     (offset < (clause->handler_offset)))
655                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
656                            
657                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
658                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
659                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
660                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
661                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
662                         else
663                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
664                 }
665
666                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
667                         return ((i + 1) << 8) | clause->flags;
668         }
669
670         return -1;
671 }
672
673 static GList*
674 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
675 {
676         MonoMethodHeader *header = cfg->header;
677         MonoExceptionClause *clause;
678         int i;
679         GList *res = NULL;
680
681         for (i = 0; i < header->num_clauses; ++i) {
682                 clause = &header->clauses [i];
683                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
684                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
685                         if (clause->flags == type)
686                                 res = g_list_append (res, clause);
687                 }
688         }
689         return res;
690 }
691
692 static void
693 mono_create_spvar_for_region (MonoCompile *cfg, int region)
694 {
695         MonoInst *var;
696
697         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
698         if (var)
699                 return;
700
701         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
702         /* prevent it from being register allocated */
703         var->flags |= MONO_INST_VOLATILE;
704
705         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
706 }
707
708 MonoInst *
709 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
710 {
711         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
712 }
713
714 static MonoInst*
715 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
716 {
717         MonoInst *var;
718
719         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
720         if (var)
721                 return var;
722
723         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
724         /* prevent it from being register allocated */
725         var->flags |= MONO_INST_VOLATILE;
726
727         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
728
729         return var;
730 }
731
732 /*
733  * Returns the type used in the eval stack when @type is loaded.
734  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
735  */
736 void
737 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
738 {
739         MonoClass *klass;
740
741         type = mini_get_underlying_type (cfg, type);
742         inst->klass = klass = mono_class_from_mono_type (type);
743         if (type->byref) {
744                 inst->type = STACK_MP;
745                 return;
746         }
747
748 handle_enum:
749         switch (type->type) {
750         case MONO_TYPE_VOID:
751                 inst->type = STACK_INV;
752                 return;
753         case MONO_TYPE_I1:
754         case MONO_TYPE_U1:
755         case MONO_TYPE_BOOLEAN:
756         case MONO_TYPE_I2:
757         case MONO_TYPE_U2:
758         case MONO_TYPE_CHAR:
759         case MONO_TYPE_I4:
760         case MONO_TYPE_U4:
761                 inst->type = STACK_I4;
762                 return;
763         case MONO_TYPE_I:
764         case MONO_TYPE_U:
765         case MONO_TYPE_PTR:
766         case MONO_TYPE_FNPTR:
767                 inst->type = STACK_PTR;
768                 return;
769         case MONO_TYPE_CLASS:
770         case MONO_TYPE_STRING:
771         case MONO_TYPE_OBJECT:
772         case MONO_TYPE_SZARRAY:
773         case MONO_TYPE_ARRAY:    
774                 inst->type = STACK_OBJ;
775                 return;
776         case MONO_TYPE_I8:
777         case MONO_TYPE_U8:
778                 inst->type = STACK_I8;
779                 return;
780         case MONO_TYPE_R4:
781                 inst->type = cfg->r4_stack_type;
782                 break;
783         case MONO_TYPE_R8:
784                 inst->type = STACK_R8;
785                 return;
786         case MONO_TYPE_VALUETYPE:
787                 if (type->data.klass->enumtype) {
788                         type = mono_class_enum_basetype (type->data.klass);
789                         goto handle_enum;
790                 } else {
791                         inst->klass = klass;
792                         inst->type = STACK_VTYPE;
793                         return;
794                 }
795         case MONO_TYPE_TYPEDBYREF:
796                 inst->klass = mono_defaults.typed_reference_class;
797                 inst->type = STACK_VTYPE;
798                 return;
799         case MONO_TYPE_GENERICINST:
800                 type = &type->data.generic_class->container_class->byval_arg;
801                 goto handle_enum;
802         case MONO_TYPE_VAR:
803         case MONO_TYPE_MVAR:
804                 g_assert (cfg->generic_sharing_context);
805                 if (mini_is_gsharedvt_type (cfg, type)) {
806                         g_assert (cfg->gsharedvt);
807                         inst->type = STACK_VTYPE;
808                 } else {
809                         type_to_eval_stack_type (cfg, mini_get_underlying_type (cfg, type), inst);
810                 }
811                 return;
812         default:
813                 g_error ("unknown type 0x%02x in eval stack type", type->type);
814         }
815 }
816
817 /*
818  * The following tables are used to quickly validate the IL code in type_from_op ().
819  */
820 static const char
821 bin_num_table [STACK_MAX] [STACK_MAX] = {
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
827         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
831 };
832
833 static const char 
834 neg_table [] = {
835         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
836 };
837
838 /* reduce the size of this table */
839 static const char
840 bin_int_table [STACK_MAX] [STACK_MAX] = {
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
849 };
850
851 static const char
852 bin_comp_table [STACK_MAX] [STACK_MAX] = {
853 /*      Inv i  L  p  F  &  O  vt r4 */
854         {0},
855         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
856         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
857         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
859         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
860         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
861         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
862         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
863 };
864
865 /* reduce the size of this table */
866 static const char
867 shift_table [STACK_MAX] [STACK_MAX] = {
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
876 };
877
878 /*
879  * Tables to map from the non-specific opcode to the matching
880  * type-specific opcode.
881  */
882 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
883 static const guint16
884 binops_op_map [STACK_MAX] = {
885         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
886 };
887
888 /* handles from CEE_NEG to CEE_CONV_U8 */
889 static const guint16
890 unops_op_map [STACK_MAX] = {
891         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
892 };
893
894 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
895 static const guint16
896 ovfops_op_map [STACK_MAX] = {
897         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, 0, OP_RCONV_TO_U2-CEE_CONV_U2
898 };
899
900 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
901 static const guint16
902 ovf2ops_op_map [STACK_MAX] = {
903         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, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
904 };
905
906 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
907 static const guint16
908 ovf3ops_op_map [STACK_MAX] = {
909         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, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
910 };
911
912 /* handles from CEE_BEQ to CEE_BLT_UN */
913 static const guint16
914 beqops_op_map [STACK_MAX] = {
915         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, 0, OP_FBEQ-CEE_BEQ
916 };
917
918 /* handles from CEE_CEQ to CEE_CLT_UN */
919 static const guint16
920 ceqops_op_map [STACK_MAX] = {
921         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, 0, OP_RCEQ-OP_CEQ
922 };
923
924 /*
925  * Sets ins->type (the type on the eval stack) according to the
926  * type of the opcode and the arguments to it.
927  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
928  *
929  * FIXME: this function sets ins->type unconditionally in some cases, but
930  * it should set it to invalid for some types (a conv.x on an object)
931  */
932 static void
933 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
934 {
935         switch (ins->opcode) {
936         /* binops */
937         case CEE_ADD:
938         case CEE_SUB:
939         case CEE_MUL:
940         case CEE_DIV:
941         case CEE_REM:
942                 /* FIXME: check unverifiable args for STACK_MP */
943                 ins->type = bin_num_table [src1->type] [src2->type];
944                 ins->opcode += binops_op_map [ins->type];
945                 break;
946         case CEE_DIV_UN:
947         case CEE_REM_UN:
948         case CEE_AND:
949         case CEE_OR:
950         case CEE_XOR:
951                 ins->type = bin_int_table [src1->type] [src2->type];
952                 ins->opcode += binops_op_map [ins->type];
953                 break;
954         case CEE_SHL:
955         case CEE_SHR:
956         case CEE_SHR_UN:
957                 ins->type = shift_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case OP_COMPARE:
961         case OP_LCOMPARE:
962         case OP_ICOMPARE:
963                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE;
966                 else if (src1->type == STACK_R4)
967                         ins->opcode = OP_RCOMPARE;
968                 else if (src1->type == STACK_R8)
969                         ins->opcode = OP_FCOMPARE;
970                 else
971                         ins->opcode = OP_ICOMPARE;
972                 break;
973         case OP_ICOMPARE_IMM:
974                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
975                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
976                         ins->opcode = OP_LCOMPARE_IMM;          
977                 break;
978         case CEE_BEQ:
979         case CEE_BGE:
980         case CEE_BGT:
981         case CEE_BLE:
982         case CEE_BLT:
983         case CEE_BNE_UN:
984         case CEE_BGE_UN:
985         case CEE_BGT_UN:
986         case CEE_BLE_UN:
987         case CEE_BLT_UN:
988                 ins->opcode += beqops_op_map [src1->type];
989                 break;
990         case OP_CEQ:
991                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
992                 ins->opcode += ceqops_op_map [src1->type];
993                 break;
994         case OP_CGT:
995         case OP_CGT_UN:
996         case OP_CLT:
997         case OP_CLT_UN:
998                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
999                 ins->opcode += ceqops_op_map [src1->type];
1000                 break;
1001         /* unops */
1002         case CEE_NEG:
1003                 ins->type = neg_table [src1->type];
1004                 ins->opcode += unops_op_map [ins->type];
1005                 break;
1006         case CEE_NOT:
1007                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1008                         ins->type = src1->type;
1009                 else
1010                         ins->type = STACK_INV;
1011                 ins->opcode += unops_op_map [ins->type];
1012                 break;
1013         case CEE_CONV_I1:
1014         case CEE_CONV_I2:
1015         case CEE_CONV_I4:
1016         case CEE_CONV_U4:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += unops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_R_UN:
1021                 ins->type = STACK_R8;
1022                 switch (src1->type) {
1023                 case STACK_I4:
1024                 case STACK_PTR:
1025                         ins->opcode = OP_ICONV_TO_R_UN;
1026                         break;
1027                 case STACK_I8:
1028                         ins->opcode = OP_LCONV_TO_R_UN; 
1029                         break;
1030                 }
1031                 break;
1032         case CEE_CONV_OVF_I1:
1033         case CEE_CONV_OVF_U1:
1034         case CEE_CONV_OVF_I2:
1035         case CEE_CONV_OVF_U2:
1036         case CEE_CONV_OVF_I4:
1037         case CEE_CONV_OVF_U4:
1038                 ins->type = STACK_I4;
1039                 ins->opcode += ovf3ops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I_UN:
1042         case CEE_CONV_OVF_U_UN:
1043                 ins->type = STACK_PTR;
1044                 ins->opcode += ovf2ops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_I1_UN:
1047         case CEE_CONV_OVF_I2_UN:
1048         case CEE_CONV_OVF_I4_UN:
1049         case CEE_CONV_OVF_U1_UN:
1050         case CEE_CONV_OVF_U2_UN:
1051         case CEE_CONV_OVF_U4_UN:
1052                 ins->type = STACK_I4;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_U:
1056                 ins->type = STACK_PTR;
1057                 switch (src1->type) {
1058                 case STACK_I4:
1059                         ins->opcode = OP_ICONV_TO_U;
1060                         break;
1061                 case STACK_PTR:
1062                 case STACK_MP:
1063 #if SIZEOF_VOID_P == 8
1064                         ins->opcode = OP_LCONV_TO_U;
1065 #else
1066                         ins->opcode = OP_MOVE;
1067 #endif
1068                         break;
1069                 case STACK_I8:
1070                         ins->opcode = OP_LCONV_TO_U;
1071                         break;
1072                 case STACK_R8:
1073                         ins->opcode = OP_FCONV_TO_U;
1074                         break;
1075                 }
1076                 break;
1077         case CEE_CONV_I8:
1078         case CEE_CONV_U8:
1079                 ins->type = STACK_I8;
1080                 ins->opcode += unops_op_map [src1->type];
1081                 break;
1082         case CEE_CONV_OVF_I8:
1083         case CEE_CONV_OVF_U8:
1084                 ins->type = STACK_I8;
1085                 ins->opcode += ovf3ops_op_map [src1->type];
1086                 break;
1087         case CEE_CONV_OVF_U8_UN:
1088         case CEE_CONV_OVF_I8_UN:
1089                 ins->type = STACK_I8;
1090                 ins->opcode += ovf2ops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R4:
1093                 ins->type = cfg->r4_stack_type;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_R8:
1097                 ins->type = STACK_R8;
1098                 ins->opcode += unops_op_map [src1->type];
1099                 break;
1100         case OP_CKFINITE:
1101                 ins->type = STACK_R8;           
1102                 break;
1103         case CEE_CONV_U2:
1104         case CEE_CONV_U1:
1105                 ins->type = STACK_I4;
1106                 ins->opcode += ovfops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_I:
1109         case CEE_CONV_OVF_I:
1110         case CEE_CONV_OVF_U:
1111                 ins->type = STACK_PTR;
1112                 ins->opcode += ovfops_op_map [src1->type];
1113                 break;
1114         case CEE_ADD_OVF:
1115         case CEE_ADD_OVF_UN:
1116         case CEE_MUL_OVF:
1117         case CEE_MUL_OVF_UN:
1118         case CEE_SUB_OVF:
1119         case CEE_SUB_OVF_UN:
1120                 ins->type = bin_num_table [src1->type] [src2->type];
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 if (ins->type == STACK_R8)
1123                         ins->type = STACK_INV;
1124                 break;
1125         case OP_LOAD_MEMBASE:
1126                 ins->type = STACK_PTR;
1127                 break;
1128         case OP_LOADI1_MEMBASE:
1129         case OP_LOADU1_MEMBASE:
1130         case OP_LOADI2_MEMBASE:
1131         case OP_LOADU2_MEMBASE:
1132         case OP_LOADI4_MEMBASE:
1133         case OP_LOADU4_MEMBASE:
1134                 ins->type = STACK_PTR;
1135                 break;
1136         case OP_LOADI8_MEMBASE:
1137                 ins->type = STACK_I8;
1138                 break;
1139         case OP_LOADR4_MEMBASE:
1140                 ins->type = cfg->r4_stack_type;
1141                 break;
1142         case OP_LOADR8_MEMBASE:
1143                 ins->type = STACK_R8;
1144                 break;
1145         default:
1146                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1147                 break;
1148         }
1149
1150         if (ins->type == STACK_MP)
1151                 ins->klass = mono_defaults.object_class;
1152 }
1153
1154 static const char 
1155 ldind_type [] = {
1156         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1157 };
1158
1159 #if 0
1160
1161 static const char
1162 param_table [STACK_MAX] [STACK_MAX] = {
1163         {0},
1164 };
1165
1166 static int
1167 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1168         int i;
1169
1170         if (sig->hasthis) {
1171                 switch (args->type) {
1172                 case STACK_I4:
1173                 case STACK_I8:
1174                 case STACK_R8:
1175                 case STACK_VTYPE:
1176                 case STACK_INV:
1177                         return 0;
1178                 }
1179                 args++;
1180         }
1181         for (i = 0; i < sig->param_count; ++i) {
1182                 switch (args [i].type) {
1183                 case STACK_INV:
1184                         return 0;
1185                 case STACK_MP:
1186                         if (!sig->params [i]->byref)
1187                                 return 0;
1188                         continue;
1189                 case STACK_OBJ:
1190                         if (sig->params [i]->byref)
1191                                 return 0;
1192                         switch (sig->params [i]->type) {
1193                         case MONO_TYPE_CLASS:
1194                         case MONO_TYPE_STRING:
1195                         case MONO_TYPE_OBJECT:
1196                         case MONO_TYPE_SZARRAY:
1197                         case MONO_TYPE_ARRAY:
1198                                 break;
1199                         default:
1200                                 return 0;
1201                         }
1202                         continue;
1203                 case STACK_R8:
1204                         if (sig->params [i]->byref)
1205                                 return 0;
1206                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1207                                 return 0;
1208                         continue;
1209                 case STACK_PTR:
1210                 case STACK_I4:
1211                 case STACK_I8:
1212                 case STACK_VTYPE:
1213                         break;
1214                 }
1215                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1216                         return 0;*/
1217         }
1218         return 1;
1219 }
1220 #endif
1221
1222 /*
1223  * When we need a pointer to the current domain many times in a method, we
1224  * call mono_domain_get() once and we store the result in a local variable.
1225  * This function returns the variable that represents the MonoDomain*.
1226  */
1227 inline static MonoInst *
1228 mono_get_domainvar (MonoCompile *cfg)
1229 {
1230         if (!cfg->domainvar)
1231                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1232         return cfg->domainvar;
1233 }
1234
1235 /*
1236  * The got_var contains the address of the Global Offset Table when AOT 
1237  * compiling.
1238  */
1239 MonoInst *
1240 mono_get_got_var (MonoCompile *cfg)
1241 {
1242 #ifdef MONO_ARCH_NEED_GOT_VAR
1243         if (!cfg->compile_aot)
1244                 return NULL;
1245         if (!cfg->got_var) {
1246                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247         }
1248         return cfg->got_var;
1249 #else
1250         return NULL;
1251 #endif
1252 }
1253
1254 static MonoInst *
1255 mono_get_vtable_var (MonoCompile *cfg)
1256 {
1257         g_assert (cfg->generic_sharing_context);
1258
1259         if (!cfg->rgctx_var) {
1260                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1261                 /* force the var to be stack allocated */
1262                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1263         }
1264
1265         return cfg->rgctx_var;
1266 }
1267
1268 static MonoType*
1269 type_from_stack_type (MonoInst *ins) {
1270         switch (ins->type) {
1271         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1272         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1273         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1274         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1275         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1276         case STACK_MP:
1277                 return &ins->klass->this_arg;
1278         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1279         case STACK_VTYPE: return &ins->klass->byval_arg;
1280         default:
1281                 g_error ("stack type %d to monotype not handled\n", ins->type);
1282         }
1283         return NULL;
1284 }
1285
1286 static G_GNUC_UNUSED int
1287 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1288 {
1289         t = mono_type_get_underlying_type (t);
1290         switch (t->type) {
1291         case MONO_TYPE_I1:
1292         case MONO_TYPE_U1:
1293         case MONO_TYPE_BOOLEAN:
1294         case MONO_TYPE_I2:
1295         case MONO_TYPE_U2:
1296         case MONO_TYPE_CHAR:
1297         case MONO_TYPE_I4:
1298         case MONO_TYPE_U4:
1299                 return STACK_I4;
1300         case MONO_TYPE_I:
1301         case MONO_TYPE_U:
1302         case MONO_TYPE_PTR:
1303         case MONO_TYPE_FNPTR:
1304                 return STACK_PTR;
1305         case MONO_TYPE_CLASS:
1306         case MONO_TYPE_STRING:
1307         case MONO_TYPE_OBJECT:
1308         case MONO_TYPE_SZARRAY:
1309         case MONO_TYPE_ARRAY:    
1310                 return STACK_OBJ;
1311         case MONO_TYPE_I8:
1312         case MONO_TYPE_U8:
1313                 return STACK_I8;
1314         case MONO_TYPE_R4:
1315                 return cfg->r4_stack_type;
1316         case MONO_TYPE_R8:
1317                 return STACK_R8;
1318         case MONO_TYPE_VALUETYPE:
1319         case MONO_TYPE_TYPEDBYREF:
1320                 return STACK_VTYPE;
1321         case MONO_TYPE_GENERICINST:
1322                 if (mono_type_generic_inst_is_valuetype (t))
1323                         return STACK_VTYPE;
1324                 else
1325                         return STACK_OBJ;
1326                 break;
1327         default:
1328                 g_assert_not_reached ();
1329         }
1330
1331         return -1;
1332 }
1333
1334 static MonoClass*
1335 array_access_to_klass (int opcode)
1336 {
1337         switch (opcode) {
1338         case CEE_LDELEM_U1:
1339                 return mono_defaults.byte_class;
1340         case CEE_LDELEM_U2:
1341                 return mono_defaults.uint16_class;
1342         case CEE_LDELEM_I:
1343         case CEE_STELEM_I:
1344                 return mono_defaults.int_class;
1345         case CEE_LDELEM_I1:
1346         case CEE_STELEM_I1:
1347                 return mono_defaults.sbyte_class;
1348         case CEE_LDELEM_I2:
1349         case CEE_STELEM_I2:
1350                 return mono_defaults.int16_class;
1351         case CEE_LDELEM_I4:
1352         case CEE_STELEM_I4:
1353                 return mono_defaults.int32_class;
1354         case CEE_LDELEM_U4:
1355                 return mono_defaults.uint32_class;
1356         case CEE_LDELEM_I8:
1357         case CEE_STELEM_I8:
1358                 return mono_defaults.int64_class;
1359         case CEE_LDELEM_R4:
1360         case CEE_STELEM_R4:
1361                 return mono_defaults.single_class;
1362         case CEE_LDELEM_R8:
1363         case CEE_STELEM_R8:
1364                 return mono_defaults.double_class;
1365         case CEE_LDELEM_REF:
1366         case CEE_STELEM_REF:
1367                 return mono_defaults.object_class;
1368         default:
1369                 g_assert_not_reached ();
1370         }
1371         return NULL;
1372 }
1373
1374 /*
1375  * We try to share variables when possible
1376  */
1377 static MonoInst *
1378 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1379 {
1380         MonoInst *res;
1381         int pos, vnum;
1382
1383         /* inlining can result in deeper stacks */ 
1384         if (slot >= cfg->header->max_stack)
1385                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1386
1387         pos = ins->type - 1 + slot * STACK_MAX;
1388
1389         switch (ins->type) {
1390         case STACK_I4:
1391         case STACK_I8:
1392         case STACK_R8:
1393         case STACK_PTR:
1394         case STACK_MP:
1395         case STACK_OBJ:
1396                 if ((vnum = cfg->intvars [pos]))
1397                         return cfg->varinfo [vnum];
1398                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1399                 cfg->intvars [pos] = res->inst_c0;
1400                 break;
1401         default:
1402                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1403         }
1404         return res;
1405 }
1406
1407 static void
1408 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1409 {
1410         /* 
1411          * Don't use this if a generic_context is set, since that means AOT can't
1412          * look up the method using just the image+token.
1413          * table == 0 means this is a reference made from a wrapper.
1414          */
1415         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1416                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1417                 jump_info_token->image = image;
1418                 jump_info_token->token = token;
1419                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1420         }
1421 }
1422
1423 /*
1424  * This function is called to handle items that are left on the evaluation stack
1425  * at basic block boundaries. What happens is that we save the values to local variables
1426  * and we reload them later when first entering the target basic block (with the
1427  * handle_loaded_temps () function).
1428  * A single joint point will use the same variables (stored in the array bb->out_stack or
1429  * bb->in_stack, if the basic block is before or after the joint point).
1430  *
1431  * This function needs to be called _before_ emitting the last instruction of
1432  * the bb (i.e. before emitting a branch).
1433  * If the stack merge fails at a join point, cfg->unverifiable is set.
1434  */
1435 static void
1436 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1437 {
1438         int i, bindex;
1439         MonoBasicBlock *bb = cfg->cbb;
1440         MonoBasicBlock *outb;
1441         MonoInst *inst, **locals;
1442         gboolean found;
1443
1444         if (!count)
1445                 return;
1446         if (cfg->verbose_level > 3)
1447                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1448         if (!bb->out_scount) {
1449                 bb->out_scount = count;
1450                 //printf ("bblock %d has out:", bb->block_num);
1451                 found = FALSE;
1452                 for (i = 0; i < bb->out_count; ++i) {
1453                         outb = bb->out_bb [i];
1454                         /* exception handlers are linked, but they should not be considered for stack args */
1455                         if (outb->flags & BB_EXCEPTION_HANDLER)
1456                                 continue;
1457                         //printf (" %d", outb->block_num);
1458                         if (outb->in_stack) {
1459                                 found = TRUE;
1460                                 bb->out_stack = outb->in_stack;
1461                                 break;
1462                         }
1463                 }
1464                 //printf ("\n");
1465                 if (!found) {
1466                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1467                         for (i = 0; i < count; ++i) {
1468                                 /* 
1469                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1470                                  * stack slot and if they are of the same type.
1471                                  * This won't cause conflicts since if 'local' is used to 
1472                                  * store one of the values in the in_stack of a bblock, then
1473                                  * the same variable will be used for the same outgoing stack 
1474                                  * slot as well. 
1475                                  * This doesn't work when inlining methods, since the bblocks
1476                                  * in the inlined methods do not inherit their in_stack from
1477                                  * the bblock they are inlined to. See bug #58863 for an
1478                                  * example.
1479                                  */
1480                                 if (cfg->inlined_method)
1481                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1482                                 else
1483                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1484                         }
1485                 }
1486         }
1487
1488         for (i = 0; i < bb->out_count; ++i) {
1489                 outb = bb->out_bb [i];
1490                 /* exception handlers are linked, but they should not be considered for stack args */
1491                 if (outb->flags & BB_EXCEPTION_HANDLER)
1492                         continue;
1493                 if (outb->in_scount) {
1494                         if (outb->in_scount != bb->out_scount) {
1495                                 cfg->unverifiable = TRUE;
1496                                 return;
1497                         }
1498                         continue; /* check they are the same locals */
1499                 }
1500                 outb->in_scount = count;
1501                 outb->in_stack = bb->out_stack;
1502         }
1503
1504         locals = bb->out_stack;
1505         cfg->cbb = bb;
1506         for (i = 0; i < count; ++i) {
1507                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1508                 inst->cil_code = sp [i]->cil_code;
1509                 sp [i] = locals [i];
1510                 if (cfg->verbose_level > 3)
1511                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1512         }
1513
1514         /*
1515          * It is possible that the out bblocks already have in_stack assigned, and
1516          * the in_stacks differ. In this case, we will store to all the different 
1517          * in_stacks.
1518          */
1519
1520         found = TRUE;
1521         bindex = 0;
1522         while (found) {
1523                 /* Find a bblock which has a different in_stack */
1524                 found = FALSE;
1525                 while (bindex < bb->out_count) {
1526                         outb = bb->out_bb [bindex];
1527                         /* exception handlers are linked, but they should not be considered for stack args */
1528                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1529                                 bindex++;
1530                                 continue;
1531                         }
1532                         if (outb->in_stack != locals) {
1533                                 for (i = 0; i < count; ++i) {
1534                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1535                                         inst->cil_code = sp [i]->cil_code;
1536                                         sp [i] = locals [i];
1537                                         if (cfg->verbose_level > 3)
1538                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1539                                 }
1540                                 locals = outb->in_stack;
1541                                 found = TRUE;
1542                                 break;
1543                         }
1544                         bindex ++;
1545                 }
1546         }
1547 }
1548
1549 /* Emit code which loads interface_offsets [klass->interface_id]
1550  * The array is stored in memory before vtable.
1551 */
1552 static void
1553 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1554 {
1555         if (cfg->compile_aot) {
1556                 int ioffset_reg = alloc_preg (cfg);
1557                 int iid_reg = alloc_preg (cfg);
1558
1559                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1560                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1562         }
1563         else {
1564                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1565         }
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         if (cfg->compile_aot)
1579                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1580         else
1581                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1582         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1583         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1584 #else
1585         int ibitmap_byte_reg = alloc_preg (cfg);
1586
1587         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1588
1589         if (cfg->compile_aot) {
1590                 int iid_reg = alloc_preg (cfg);
1591                 int shifted_iid_reg = alloc_preg (cfg);
1592                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1593                 int masked_iid_reg = alloc_preg (cfg);
1594                 int iid_one_bit_reg = alloc_preg (cfg);
1595                 int iid_bit_reg = alloc_preg (cfg);
1596                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1598                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1599                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1600                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1601                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1602                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1604         } else {
1605                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1606                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1607         }
1608 #endif
1609 }
1610
1611 /* 
1612  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1613  * stored in "klass_reg" implements the interface "klass".
1614  */
1615 static void
1616 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1617 {
1618         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1619 }
1620
1621 /* 
1622  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1623  * stored in "vtable_reg" implements the interface "klass".
1624  */
1625 static void
1626 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1627 {
1628         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1629 }
1630
1631 /* 
1632  * Emit code which checks whenever the interface id of @klass is smaller than
1633  * than the value given by max_iid_reg.
1634 */
1635 static void
1636 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1637                                                  MonoBasicBlock *false_target)
1638 {
1639         if (cfg->compile_aot) {
1640                 int iid_reg = alloc_preg (cfg);
1641                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1642                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1643         }
1644         else
1645                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1646         if (false_target)
1647                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1648         else
1649                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1650 }
1651
1652 /* Same as above, but obtains max_iid from a vtable */
1653 static void
1654 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1655                                                                  MonoBasicBlock *false_target)
1656 {
1657         int max_iid_reg = alloc_preg (cfg);
1658                 
1659         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1660         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1661 }
1662
1663 /* Same as above, but obtains max_iid from a klass */
1664 static void
1665 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1666                                                                  MonoBasicBlock *false_target)
1667 {
1668         int max_iid_reg = alloc_preg (cfg);
1669
1670         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1671         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1672 }
1673
1674 static void
1675 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1676 {
1677         int idepth_reg = alloc_preg (cfg);
1678         int stypes_reg = alloc_preg (cfg);
1679         int stype = alloc_preg (cfg);
1680
1681         mono_class_setup_supertypes (klass);
1682
1683         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1684                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1685                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1686                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1687         }
1688         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1689         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1690         if (klass_ins) {
1691                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1692         } else if (cfg->compile_aot) {
1693                 int const_reg = alloc_preg (cfg);
1694                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1695                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1696         } else {
1697                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1698         }
1699         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1700 }
1701
1702 static void
1703 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1704 {
1705         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1706 }
1707
1708 static void
1709 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1710 {
1711         int intf_reg = alloc_preg (cfg);
1712
1713         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1714         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1715         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1716         if (true_target)
1717                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1718         else
1719                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1720 }
1721
1722 /*
1723  * Variant of the above that takes a register to the class, not the vtable.
1724  */
1725 static void
1726 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1727 {
1728         int intf_bit_reg = alloc_preg (cfg);
1729
1730         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1731         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1732         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1733         if (true_target)
1734                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1735         else
1736                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1737 }
1738
1739 static inline void
1740 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1741 {
1742         if (klass_inst) {
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1744         } else if (cfg->compile_aot) {
1745                 int const_reg = alloc_preg (cfg);
1746                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1748         } else {
1749                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1750         }
1751         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1752 }
1753
1754 static inline void
1755 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1756 {
1757         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1758 }
1759
1760 static inline void
1761 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1762 {
1763         if (cfg->compile_aot) {
1764                 int const_reg = alloc_preg (cfg);
1765                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1766                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1767         } else {
1768                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1769         }
1770         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1771 }
1772
1773 static void
1774 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1775         
1776 static void
1777 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1778 {
1779         if (klass->rank) {
1780                 int rank_reg = alloc_preg (cfg);
1781                 int eclass_reg = alloc_preg (cfg);
1782
1783                 g_assert (!klass_inst);
1784                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1785                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1786                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1787                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1789                 if (klass->cast_class == mono_defaults.object_class) {
1790                         int parent_reg = alloc_preg (cfg);
1791                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1792                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1793                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1794                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1795                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1796                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1797                 } else if (klass->cast_class == mono_defaults.enum_class) {
1798                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1799                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1800                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1801                 } else {
1802                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1803                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1804                 }
1805
1806                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1807                         /* Check that the object is a vector too */
1808                         int bounds_reg = alloc_preg (cfg);
1809                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1810                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1811                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1812                 }
1813         } else {
1814                 int idepth_reg = alloc_preg (cfg);
1815                 int stypes_reg = alloc_preg (cfg);
1816                 int stype = alloc_preg (cfg);
1817
1818                 mono_class_setup_supertypes (klass);
1819
1820                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1821                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1822                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1823                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1824                 }
1825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1827                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1828         }
1829 }
1830
1831 static void
1832 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1833 {
1834         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1835 }
1836
1837 static void 
1838 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1839 {
1840         int val_reg;
1841
1842         g_assert (val == 0);
1843
1844         if (align == 0)
1845                 align = 4;
1846
1847         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1848                 switch (size) {
1849                 case 1:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852                 case 2:
1853                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1854                         return;
1855                 case 4:
1856                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1857                         return;
1858 #if SIZEOF_REGISTER == 8
1859                 case 8:
1860                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1861                         return;
1862 #endif
1863                 }
1864         }
1865
1866         val_reg = alloc_preg (cfg);
1867
1868         if (SIZEOF_REGISTER == 8)
1869                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1870         else
1871                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1872
1873         if (align < 4) {
1874                 /* This could be optimized further if neccesary */
1875                 while (size >= 1) {
1876                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                         offset += 1;
1878                         size -= 1;
1879                 }
1880                 return;
1881         }       
1882
1883 #if !NO_UNALIGNED_ACCESS
1884         if (SIZEOF_REGISTER == 8) {
1885                 if (offset % 8) {
1886                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1887                         offset += 4;
1888                         size -= 4;
1889                 }
1890                 while (size >= 8) {
1891                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1892                         offset += 8;
1893                         size -= 8;
1894                 }
1895         }       
1896 #endif
1897
1898         while (size >= 4) {
1899                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1900                 offset += 4;
1901                 size -= 4;
1902         }
1903         while (size >= 2) {
1904                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1905                 offset += 2;
1906                 size -= 2;
1907         }
1908         while (size >= 1) {
1909                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1910                 offset += 1;
1911                 size -= 1;
1912         }
1913 }
1914
1915 void 
1916 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1917 {
1918         int cur_reg;
1919
1920         if (align == 0)
1921                 align = 4;
1922
1923         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1924         g_assert (size < 10000);
1925
1926         if (align < 4) {
1927                 /* This could be optimized further if neccesary */
1928                 while (size >= 1) {
1929                         cur_reg = alloc_preg (cfg);
1930                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1931                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1932                         doffset += 1;
1933                         soffset += 1;
1934                         size -= 1;
1935                 }
1936         }
1937
1938 #if !NO_UNALIGNED_ACCESS
1939         if (SIZEOF_REGISTER == 8) {
1940                 while (size >= 8) {
1941                         cur_reg = alloc_preg (cfg);
1942                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1943                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1944                         doffset += 8;
1945                         soffset += 8;
1946                         size -= 8;
1947                 }
1948         }       
1949 #endif
1950
1951         while (size >= 4) {
1952                 cur_reg = alloc_preg (cfg);
1953                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1954                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1955                 doffset += 4;
1956                 soffset += 4;
1957                 size -= 4;
1958         }
1959         while (size >= 2) {
1960                 cur_reg = alloc_preg (cfg);
1961                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1962                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1963                 doffset += 2;
1964                 soffset += 2;
1965                 size -= 2;
1966         }
1967         while (size >= 1) {
1968                 cur_reg = alloc_preg (cfg);
1969                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1970                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1971                 doffset += 1;
1972                 soffset += 1;
1973                 size -= 1;
1974         }
1975 }
1976
1977 static void
1978 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1979 {
1980         MonoInst *ins, *c;
1981
1982         if (cfg->compile_aot) {
1983                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1984                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1985                 ins->sreg1 = sreg1;
1986                 ins->sreg2 = c->dreg;
1987                 MONO_ADD_INS (cfg->cbb, ins);
1988         } else {
1989                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1990                 ins->sreg1 = sreg1;
1991                 ins->inst_offset = mini_get_tls_offset (tls_key);
1992                 MONO_ADD_INS (cfg->cbb, ins);
1993         }
1994 }
1995
1996 /*
1997  * emit_push_lmf:
1998  *
1999  *   Emit IR to push the current LMF onto the LMF stack.
2000  */
2001 static void
2002 emit_push_lmf (MonoCompile *cfg)
2003 {
2004         /*
2005          * Emit IR to push the LMF:
2006          * lmf_addr = <lmf_addr from tls>
2007          * lmf->lmf_addr = lmf_addr
2008          * lmf->prev_lmf = *lmf_addr
2009          * *lmf_addr = lmf
2010          */
2011         int lmf_reg, prev_lmf_reg;
2012         MonoInst *ins, *lmf_ins;
2013
2014         if (!cfg->lmf_ir)
2015                 return;
2016
2017         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2018                 /* Load current lmf */
2019                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2020                 g_assert (lmf_ins);
2021                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2022                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2023                 lmf_reg = ins->dreg;
2024                 /* Save previous_lmf */
2025                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2026                 /* Set new LMF */
2027                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2028         } else {
2029                 /*
2030                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2031                  */
2032                 if (!cfg->lmf_addr_var)
2033                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2034
2035 #ifdef HOST_WIN32
2036                 ins = mono_get_jit_tls_intrinsic (cfg);
2037                 if (ins) {
2038                         int jit_tls_dreg = ins->dreg;
2039
2040                         MONO_ADD_INS (cfg->cbb, ins);
2041                         lmf_reg = alloc_preg (cfg);
2042                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2043                 } else {
2044                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2045                 }
2046 #else
2047                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2048                 if (lmf_ins) {
2049                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2050                 } else {
2051 #ifdef TARGET_IOS
2052                         MonoInst *args [16], *jit_tls_ins, *ins;
2053
2054                         /* Inline mono_get_lmf_addr () */
2055                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2056
2057                         /* Load mono_jit_tls_id */
2058                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2059                         /* call pthread_getspecific () */
2060                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2061                         /* lmf_addr = &jit_tls->lmf */
2062                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2063                         lmf_ins = ins;
2064 #else
2065                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2066 #endif
2067                 }
2068 #endif
2069                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2070
2071                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2072                 lmf_reg = ins->dreg;
2073
2074                 prev_lmf_reg = alloc_preg (cfg);
2075                 /* Save previous_lmf */
2076                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2077                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2078                 /* Set new lmf */
2079                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2080         }
2081 }
2082
2083 /*
2084  * emit_pop_lmf:
2085  *
2086  *   Emit IR to pop the current LMF from the LMF stack.
2087  */
2088 static void
2089 emit_pop_lmf (MonoCompile *cfg)
2090 {
2091         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2092         MonoInst *ins;
2093
2094         if (!cfg->lmf_ir)
2095                 return;
2096
2097         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2098         lmf_reg = ins->dreg;
2099
2100         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2101                 /* Load previous_lmf */
2102                 prev_lmf_reg = alloc_preg (cfg);
2103                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2104                 /* Set new LMF */
2105                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2106         } else {
2107                 /*
2108                  * Emit IR to pop the LMF:
2109                  * *(lmf->lmf_addr) = lmf->prev_lmf
2110                  */
2111                 /* This could be called before emit_push_lmf () */
2112                 if (!cfg->lmf_addr_var)
2113                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2114                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2115
2116                 prev_lmf_reg = alloc_preg (cfg);
2117                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2118                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2119         }
2120 }
2121
2122 static void
2123 emit_instrumentation_call (MonoCompile *cfg, void *func)
2124 {
2125         MonoInst *iargs [1];
2126
2127         /*
2128          * Avoid instrumenting inlined methods since it can
2129          * distort profiling results.
2130          */
2131         if (cfg->method != cfg->current_method)
2132                 return;
2133
2134         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2135                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2136                 mono_emit_jit_icall (cfg, func, iargs);
2137         }
2138 }
2139
2140 static int
2141 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2142 {
2143 handle_enum:
2144         type = mini_get_underlying_type (cfg, type);
2145         switch (type->type) {
2146         case MONO_TYPE_VOID:
2147                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2148         case MONO_TYPE_I1:
2149         case MONO_TYPE_U1:
2150         case MONO_TYPE_BOOLEAN:
2151         case MONO_TYPE_I2:
2152         case MONO_TYPE_U2:
2153         case MONO_TYPE_CHAR:
2154         case MONO_TYPE_I4:
2155         case MONO_TYPE_U4:
2156                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2157         case MONO_TYPE_I:
2158         case MONO_TYPE_U:
2159         case MONO_TYPE_PTR:
2160         case MONO_TYPE_FNPTR:
2161                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2162         case MONO_TYPE_CLASS:
2163         case MONO_TYPE_STRING:
2164         case MONO_TYPE_OBJECT:
2165         case MONO_TYPE_SZARRAY:
2166         case MONO_TYPE_ARRAY:    
2167                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2168         case MONO_TYPE_I8:
2169         case MONO_TYPE_U8:
2170                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2171         case MONO_TYPE_R4:
2172                 if (cfg->r4fp)
2173                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2174                 else
2175                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2176         case MONO_TYPE_R8:
2177                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2178         case MONO_TYPE_VALUETYPE:
2179                 if (type->data.klass->enumtype) {
2180                         type = mono_class_enum_basetype (type->data.klass);
2181                         goto handle_enum;
2182                 } else
2183                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         case MONO_TYPE_TYPEDBYREF:
2185                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2186         case MONO_TYPE_GENERICINST:
2187                 type = &type->data.generic_class->container_class->byval_arg;
2188                 goto handle_enum;
2189         case MONO_TYPE_VAR:
2190         case MONO_TYPE_MVAR:
2191                 /* gsharedvt */
2192                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2193         default:
2194                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2195         }
2196         return -1;
2197 }
2198
2199 /*
2200  * target_type_is_incompatible:
2201  * @cfg: MonoCompile context
2202  *
2203  * Check that the item @arg on the evaluation stack can be stored
2204  * in the target type (can be a local, or field, etc).
2205  * The cfg arg can be used to check if we need verification or just
2206  * validity checks.
2207  *
2208  * Returns: non-0 value if arg can't be stored on a target.
2209  */
2210 static int
2211 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2212 {
2213         MonoType *simple_type;
2214         MonoClass *klass;
2215
2216         if (target->byref) {
2217                 /* FIXME: check that the pointed to types match */
2218                 if (arg->type == STACK_MP)
2219                         return arg->klass != mono_class_from_mono_type (target);
2220                 if (arg->type == STACK_PTR)
2221                         return 0;
2222                 return 1;
2223         }
2224
2225         simple_type = mini_get_underlying_type (cfg, target);
2226         switch (simple_type->type) {
2227         case MONO_TYPE_VOID:
2228                 return 1;
2229         case MONO_TYPE_I1:
2230         case MONO_TYPE_U1:
2231         case MONO_TYPE_BOOLEAN:
2232         case MONO_TYPE_I2:
2233         case MONO_TYPE_U2:
2234         case MONO_TYPE_CHAR:
2235         case MONO_TYPE_I4:
2236         case MONO_TYPE_U4:
2237                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2238                         return 1;
2239                 return 0;
2240         case MONO_TYPE_PTR:
2241                 /* STACK_MP is needed when setting pinned locals */
2242                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2243                         return 1;
2244                 return 0;
2245         case MONO_TYPE_I:
2246         case MONO_TYPE_U:
2247         case MONO_TYPE_FNPTR:
2248                 /* 
2249                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2250                  * in native int. (#688008).
2251                  */
2252                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_CLASS:
2256         case MONO_TYPE_STRING:
2257         case MONO_TYPE_OBJECT:
2258         case MONO_TYPE_SZARRAY:
2259         case MONO_TYPE_ARRAY:    
2260                 if (arg->type != STACK_OBJ)
2261                         return 1;
2262                 /* FIXME: check type compatibility */
2263                 return 0;
2264         case MONO_TYPE_I8:
2265         case MONO_TYPE_U8:
2266                 if (arg->type != STACK_I8)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_R4:
2270                 if (arg->type != cfg->r4_stack_type)
2271                         return 1;
2272                 return 0;
2273         case MONO_TYPE_R8:
2274                 if (arg->type != STACK_R8)
2275                         return 1;
2276                 return 0;
2277         case MONO_TYPE_VALUETYPE:
2278                 if (arg->type != STACK_VTYPE)
2279                         return 1;
2280                 klass = mono_class_from_mono_type (simple_type);
2281                 if (klass != arg->klass)
2282                         return 1;
2283                 return 0;
2284         case MONO_TYPE_TYPEDBYREF:
2285                 if (arg->type != STACK_VTYPE)
2286                         return 1;
2287                 klass = mono_class_from_mono_type (simple_type);
2288                 if (klass != arg->klass)
2289                         return 1;
2290                 return 0;
2291         case MONO_TYPE_GENERICINST:
2292                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2293                         if (arg->type != STACK_VTYPE)
2294                                 return 1;
2295                         klass = mono_class_from_mono_type (simple_type);
2296                         if (klass != arg->klass)
2297                                 return 1;
2298                         return 0;
2299                 } else {
2300                         if (arg->type != STACK_OBJ)
2301                                 return 1;
2302                         /* FIXME: check type compatibility */
2303                         return 0;
2304                 }
2305         case MONO_TYPE_VAR:
2306         case MONO_TYPE_MVAR:
2307                 g_assert (cfg->generic_sharing_context);
2308                 if (mini_type_var_is_vt (cfg, simple_type)) {
2309                         if (arg->type != STACK_VTYPE)
2310                                 return 1;
2311                 } else {
2312                         if (arg->type != STACK_OBJ)
2313                                 return 1;
2314                 }
2315                 return 0;
2316         default:
2317                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2318         }
2319         return 1;
2320 }
2321
2322 /*
2323  * Prepare arguments for passing to a function call.
2324  * Return a non-zero value if the arguments can't be passed to the given
2325  * signature.
2326  * The type checks are not yet complete and some conversions may need
2327  * casts on 32 or 64 bit architectures.
2328  *
2329  * FIXME: implement this using target_type_is_incompatible ()
2330  */
2331 static int
2332 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2333 {
2334         MonoType *simple_type;
2335         int i;
2336
2337         if (sig->hasthis) {
2338                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2339                         return 1;
2340                 args++;
2341         }
2342         for (i = 0; i < sig->param_count; ++i) {
2343                 if (sig->params [i]->byref) {
2344                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2345                                 return 1;
2346                         continue;
2347                 }
2348                 simple_type = mini_get_underlying_type (cfg, sig->params [i]);
2349 handle_enum:
2350                 switch (simple_type->type) {
2351                 case MONO_TYPE_VOID:
2352                         return 1;
2353                         continue;
2354                 case MONO_TYPE_I1:
2355                 case MONO_TYPE_U1:
2356                 case MONO_TYPE_BOOLEAN:
2357                 case MONO_TYPE_I2:
2358                 case MONO_TYPE_U2:
2359                 case MONO_TYPE_CHAR:
2360                 case MONO_TYPE_I4:
2361                 case MONO_TYPE_U4:
2362                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_I:
2366                 case MONO_TYPE_U:
2367                 case MONO_TYPE_PTR:
2368                 case MONO_TYPE_FNPTR:
2369                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_CLASS:
2373                 case MONO_TYPE_STRING:
2374                 case MONO_TYPE_OBJECT:
2375                 case MONO_TYPE_SZARRAY:
2376                 case MONO_TYPE_ARRAY:    
2377                         if (args [i]->type != STACK_OBJ)
2378                                 return 1;
2379                         continue;
2380                 case MONO_TYPE_I8:
2381                 case MONO_TYPE_U8:
2382                         if (args [i]->type != STACK_I8)
2383                                 return 1;
2384                         continue;
2385                 case MONO_TYPE_R4:
2386                         if (args [i]->type != cfg->r4_stack_type)
2387                                 return 1;
2388                         continue;
2389                 case MONO_TYPE_R8:
2390                         if (args [i]->type != STACK_R8)
2391                                 return 1;
2392                         continue;
2393                 case MONO_TYPE_VALUETYPE:
2394                         if (simple_type->data.klass->enumtype) {
2395                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2396                                 goto handle_enum;
2397                         }
2398                         if (args [i]->type != STACK_VTYPE)
2399                                 return 1;
2400                         continue;
2401                 case MONO_TYPE_TYPEDBYREF:
2402                         if (args [i]->type != STACK_VTYPE)
2403                                 return 1;
2404                         continue;
2405                 case MONO_TYPE_GENERICINST:
2406                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2407                         goto handle_enum;
2408                 case MONO_TYPE_VAR:
2409                 case MONO_TYPE_MVAR:
2410                         /* gsharedvt */
2411                         if (args [i]->type != STACK_VTYPE)
2412                                 return 1;
2413                         continue;
2414                 default:
2415                         g_error ("unknown type 0x%02x in check_call_signature",
2416                                  simple_type->type);
2417                 }
2418         }
2419         return 0;
2420 }
2421
2422 static int
2423 callvirt_to_call (int opcode)
2424 {
2425         switch (opcode) {
2426         case OP_CALL_MEMBASE:
2427                 return OP_CALL;
2428         case OP_VOIDCALL_MEMBASE:
2429                 return OP_VOIDCALL;
2430         case OP_FCALL_MEMBASE:
2431                 return OP_FCALL;
2432         case OP_RCALL_MEMBASE:
2433                 return OP_RCALL;
2434         case OP_VCALL_MEMBASE:
2435                 return OP_VCALL;
2436         case OP_LCALL_MEMBASE:
2437                 return OP_LCALL;
2438         default:
2439                 g_assert_not_reached ();
2440         }
2441
2442         return -1;
2443 }
2444
2445 /* Either METHOD or IMT_ARG needs to be set */
2446 static void
2447 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2448 {
2449         int method_reg;
2450
2451         if (COMPILE_LLVM (cfg)) {
2452                 method_reg = alloc_preg (cfg);
2453
2454                 if (imt_arg) {
2455                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2456                 } else if (cfg->compile_aot) {
2457                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2458                 } else {
2459                         MonoInst *ins;
2460                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2461                         ins->inst_p0 = method;
2462                         ins->dreg = method_reg;
2463                         MONO_ADD_INS (cfg->cbb, ins);
2464                 }
2465
2466 #ifdef ENABLE_LLVM
2467                 call->imt_arg_reg = method_reg;
2468 #endif
2469 #ifdef MONO_ARCH_IMT_REG
2470         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2471 #else
2472         /* Need this to keep the IMT arg alive */
2473         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2474 #endif
2475                 return;
2476         }
2477
2478 #ifdef MONO_ARCH_IMT_REG
2479         method_reg = alloc_preg (cfg);
2480
2481         if (imt_arg) {
2482                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2483         } else if (cfg->compile_aot) {
2484                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2485         } else {
2486                 MonoInst *ins;
2487                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2488                 ins->inst_p0 = method;
2489                 ins->dreg = method_reg;
2490                 MONO_ADD_INS (cfg->cbb, ins);
2491         }
2492
2493         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2494 #else
2495         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2496 #endif
2497 }
2498
2499 static MonoJumpInfo *
2500 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2501 {
2502         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2503
2504         ji->ip.i = ip;
2505         ji->type = type;
2506         ji->data.target = target;
2507
2508         return ji;
2509 }
2510
2511 static int
2512 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2513 {
2514         if (cfg->generic_sharing_context)
2515                 return mono_class_check_context_used (klass);
2516         else
2517                 return 0;
2518 }
2519
2520 static int
2521 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2522 {
2523         if (cfg->generic_sharing_context)
2524                 return mono_method_check_context_used (method);
2525         else
2526                 return 0;
2527 }
2528
2529 /*
2530  * check_method_sharing:
2531  *
2532  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2533  */
2534 static void
2535 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2536 {
2537         gboolean pass_vtable = FALSE;
2538         gboolean pass_mrgctx = FALSE;
2539
2540         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2541                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2542                 gboolean sharable = FALSE;
2543
2544                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2545                         sharable = TRUE;
2546                 } else {
2547                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2548                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2549                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2550
2551                         sharable = sharing_enabled && context_sharable;
2552                 }
2553
2554                 /*
2555                  * Pass vtable iff target method might
2556                  * be shared, which means that sharing
2557                  * is enabled for its class and its
2558                  * context is sharable (and it's not a
2559                  * generic method).
2560                  */
2561                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2562                         pass_vtable = TRUE;
2563         }
2564
2565         if (mini_method_get_context (cmethod) &&
2566                 mini_method_get_context (cmethod)->method_inst) {
2567                 g_assert (!pass_vtable);
2568
2569                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2570                         pass_mrgctx = TRUE;
2571                 } else {
2572                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2573                         MonoGenericContext *context = mini_method_get_context (cmethod);
2574                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2575
2576                         if (sharing_enabled && context_sharable)
2577                                 pass_mrgctx = TRUE;
2578                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2579                                 pass_mrgctx = TRUE;
2580                 }
2581         }
2582
2583         if (out_pass_vtable)
2584                 *out_pass_vtable = pass_vtable;
2585         if (out_pass_mrgctx)
2586                 *out_pass_mrgctx = pass_mrgctx;
2587 }
2588
2589 inline static MonoCallInst *
2590 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2591                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2592 {
2593         MonoType *sig_ret;
2594         MonoCallInst *call;
2595 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2596         int i;
2597 #endif
2598
2599         if (tail) {
2600                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2601
2602                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2603         } else
2604                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual, cfg->generic_sharing_context));
2605
2606         call->args = args;
2607         call->signature = sig;
2608         call->rgctx_reg = rgctx;
2609         sig_ret = mini_get_underlying_type (cfg, sig->ret);
2610
2611         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2612
2613         if (tail) {
2614                 if (mini_type_is_vtype (cfg, sig_ret)) {
2615                         call->vret_var = cfg->vret_addr;
2616                         //g_assert_not_reached ();
2617                 }
2618         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2619                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2620                 MonoInst *loada;
2621
2622                 temp->backend.is_pinvoke = sig->pinvoke;
2623
2624                 /*
2625                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2626                  * address of return value to increase optimization opportunities.
2627                  * Before vtype decomposition, the dreg of the call ins itself represents the
2628                  * fact the call modifies the return value. After decomposition, the call will
2629                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2630                  * will be transformed into an LDADDR.
2631                  */
2632                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2633                 loada->dreg = alloc_preg (cfg);
2634                 loada->inst_p0 = temp;
2635                 /* We reference the call too since call->dreg could change during optimization */
2636                 loada->inst_p1 = call;
2637                 MONO_ADD_INS (cfg->cbb, loada);
2638
2639                 call->inst.dreg = temp->dreg;
2640
2641                 call->vret_var = loada;
2642         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2643                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2644
2645 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2646         if (COMPILE_SOFT_FLOAT (cfg)) {
2647                 /* 
2648                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2649                  * an icall, but that cannot be done during the call sequence since it would clobber
2650                  * the call registers + the stack. So we do it before emitting the call.
2651                  */
2652                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2653                         MonoType *t;
2654                         MonoInst *in = call->args [i];
2655
2656                         if (i >= sig->hasthis)
2657                                 t = sig->params [i - sig->hasthis];
2658                         else
2659                                 t = &mono_defaults.int_class->byval_arg;
2660                         t = mono_type_get_underlying_type (t);
2661
2662                         if (!t->byref && t->type == MONO_TYPE_R4) {
2663                                 MonoInst *iargs [1];
2664                                 MonoInst *conv;
2665
2666                                 iargs [0] = in;
2667                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2668
2669                                 /* The result will be in an int vreg */
2670                                 call->args [i] = conv;
2671                         }
2672                 }
2673         }
2674 #endif
2675
2676         call->need_unbox_trampoline = unbox_trampoline;
2677
2678 #ifdef ENABLE_LLVM
2679         if (COMPILE_LLVM (cfg))
2680                 mono_llvm_emit_call (cfg, call);
2681         else
2682                 mono_arch_emit_call (cfg, call);
2683 #else
2684         mono_arch_emit_call (cfg, call);
2685 #endif
2686
2687         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2688         cfg->flags |= MONO_CFG_HAS_CALLS;
2689         
2690         return call;
2691 }
2692
2693 static void
2694 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2695 {
2696 #ifdef MONO_ARCH_RGCTX_REG
2697         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2698         cfg->uses_rgctx_reg = TRUE;
2699         call->rgctx_reg = TRUE;
2700 #ifdef ENABLE_LLVM
2701         call->rgctx_arg_reg = rgctx_reg;
2702 #endif
2703 #else
2704         NOT_IMPLEMENTED;
2705 #endif
2706 }       
2707
2708 inline static MonoInst*
2709 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2710 {
2711         MonoCallInst *call;
2712         MonoInst *ins;
2713         int rgctx_reg = -1;
2714         gboolean check_sp = FALSE;
2715
2716         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2717                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2718
2719                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2720                         check_sp = TRUE;
2721         }
2722
2723         if (rgctx_arg) {
2724                 rgctx_reg = mono_alloc_preg (cfg);
2725                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2726         }
2727
2728         if (check_sp) {
2729                 if (!cfg->stack_inbalance_var)
2730                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2731
2732                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2733                 ins->dreg = cfg->stack_inbalance_var->dreg;
2734                 MONO_ADD_INS (cfg->cbb, ins);
2735         }
2736
2737         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2738
2739         call->inst.sreg1 = addr->dreg;
2740
2741         if (imt_arg)
2742                 emit_imt_argument (cfg, call, NULL, imt_arg);
2743
2744         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2745
2746         if (check_sp) {
2747                 int sp_reg;
2748
2749                 sp_reg = mono_alloc_preg (cfg);
2750
2751                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2752                 ins->dreg = sp_reg;
2753                 MONO_ADD_INS (cfg->cbb, ins);
2754
2755                 /* Restore the stack so we don't crash when throwing the exception */
2756                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2757                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2758                 MONO_ADD_INS (cfg->cbb, ins);
2759
2760                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2761                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2762         }
2763
2764         if (rgctx_arg)
2765                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2766
2767         return (MonoInst*)call;
2768 }
2769
2770 static MonoInst*
2771 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2772
2773 static MonoInst*
2774 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2775 static MonoInst*
2776 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2777
2778 static MonoInst*
2779 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2780                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2781 {
2782 #ifndef DISABLE_REMOTING
2783         gboolean might_be_remote = FALSE;
2784 #endif
2785         gboolean virtual = this != NULL;
2786         gboolean enable_for_aot = TRUE;
2787         int context_used;
2788         MonoCallInst *call;
2789         int rgctx_reg = 0;
2790         gboolean need_unbox_trampoline;
2791
2792         if (!sig)
2793                 sig = mono_method_signature (method);
2794
2795         if (rgctx_arg) {
2796                 rgctx_reg = mono_alloc_preg (cfg);
2797                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2798         }
2799
2800         if (method->string_ctor) {
2801                 /* Create the real signature */
2802                 /* FIXME: Cache these */
2803                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2804                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2805
2806                 sig = ctor_sig;
2807         }
2808
2809         context_used = mini_method_check_context_used (cfg, method);
2810
2811 #ifndef DISABLE_REMOTING
2812         might_be_remote = this && sig->hasthis &&
2813                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2814                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2815
2816         if (might_be_remote && context_used) {
2817                 MonoInst *addr;
2818
2819                 g_assert (cfg->generic_sharing_context);
2820
2821                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2822
2823                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2824         }
2825 #endif
2826
2827         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2828
2829         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2830
2831 #ifndef DISABLE_REMOTING
2832         if (might_be_remote)
2833                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2834         else
2835 #endif
2836                 call->method = method;
2837         call->inst.flags |= MONO_INST_HAS_METHOD;
2838         call->inst.inst_left = this;
2839         call->tail_call = tail;
2840
2841         if (virtual) {
2842                 int vtable_reg, slot_reg, this_reg;
2843                 int offset;
2844
2845                 this_reg = this->dreg;
2846
2847                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2848                         MonoInst *dummy_use;
2849
2850                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2851
2852                         /* Make a call to delegate->invoke_impl */
2853                         call->inst.inst_basereg = this_reg;
2854                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2855                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2856
2857                         /* We must emit a dummy use here because the delegate trampoline will
2858                         replace the 'this' argument with the delegate target making this activation
2859                         no longer a root for the delegate.
2860                         This is an issue for delegates that target collectible code such as dynamic
2861                         methods of GC'able assemblies.
2862
2863                         For a test case look into #667921.
2864
2865                         FIXME: a dummy use is not the best way to do it as the local register allocator
2866                         will put it on a caller save register and spil it around the call. 
2867                         Ideally, we would either put it on a callee save register or only do the store part.  
2868                          */
2869                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2870
2871                         return (MonoInst*)call;
2872                 }
2873
2874                 if ((!cfg->compile_aot || enable_for_aot) && 
2875                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2876                          (MONO_METHOD_IS_FINAL (method) &&
2877                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2878                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2879                         /* 
2880                          * the method is not virtual, we just need to ensure this is not null
2881                          * and then we can call the method directly.
2882                          */
2883 #ifndef DISABLE_REMOTING
2884                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2885                                 /* 
2886                                  * The check above ensures method is not gshared, this is needed since
2887                                  * gshared methods can't have wrappers.
2888                                  */
2889                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2890                         }
2891 #endif
2892
2893                         if (!method->string_ctor)
2894                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2895
2896                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2897                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2898                         /*
2899                          * the method is virtual, but we can statically dispatch since either
2900                          * it's class or the method itself are sealed.
2901                          * But first we need to ensure it's not a null reference.
2902                          */
2903                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2904
2905                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2906                 } else {
2907                         vtable_reg = alloc_preg (cfg);
2908                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2909                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2910                                 slot_reg = -1;
2911                                 if (mono_use_imt) {
2912                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2913                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2914                                         slot_reg = vtable_reg;
2915                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2916                                 }
2917                                 if (slot_reg == -1) {
2918                                         slot_reg = alloc_preg (cfg);
2919                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2920                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2921                                 }
2922                         } else {
2923                                 slot_reg = vtable_reg;
2924                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2925                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2926                                 if (imt_arg) {
2927                                         g_assert (mono_method_signature (method)->generic_param_count);
2928                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2929                                 }
2930                         }
2931
2932                         call->inst.sreg1 = slot_reg;
2933                         call->inst.inst_offset = offset;
2934                         call->virtual = TRUE;
2935                 }
2936         }
2937
2938         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2939
2940         if (rgctx_arg)
2941                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2942
2943         return (MonoInst*)call;
2944 }
2945
2946 MonoInst*
2947 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2948 {
2949         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2950 }
2951
2952 MonoInst*
2953 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2954                                            MonoInst **args)
2955 {
2956         MonoCallInst *call;
2957
2958         g_assert (sig);
2959
2960         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2961         call->fptr = func;
2962
2963         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2964
2965         return (MonoInst*)call;
2966 }
2967
2968 MonoInst*
2969 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2970 {
2971         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2972
2973         g_assert (info);
2974
2975         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2976 }
2977
2978 /*
2979  * mono_emit_abs_call:
2980  *
2981  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2982  */
2983 inline static MonoInst*
2984 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2985                                         MonoMethodSignature *sig, MonoInst **args)
2986 {
2987         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2988         MonoInst *ins;
2989
2990         /* 
2991          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2992          * handle it.
2993          */
2994         if (cfg->abs_patches == NULL)
2995                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2996         g_hash_table_insert (cfg->abs_patches, ji, ji);
2997         ins = mono_emit_native_call (cfg, ji, sig, args);
2998         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2999         return ins;
3000 }
3001
3002 MonoInst*
3003 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args, MonoBasicBlock **out_cbb)
3004 {
3005         gboolean no_wrapper = FALSE;
3006
3007         /*
3008          * Call the jit icall without a wrapper if possible.
3009          * The wrapper is needed for the following reasons:
3010          * - to handle exceptions thrown using mono_raise_exceptions () from the
3011          *   icall function. The EH code needs the lmf frame pushed by the
3012          *   wrapper to be able to unwind back to managed code.
3013          * - to be able to do stack walks for asynchronously suspended
3014          *   threads when debugging.
3015          */
3016         if (info->no_raise) {
3017                 if (cfg->compile_aot) {
3018                         // FIXME: This might be loaded into a runtime during debugging
3019                         // even if it is not compiled using 'soft-debug'.
3020                 } else {
3021                         no_wrapper = TRUE;
3022                         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3023                         if ((cfg->compile_llvm && SIZEOF_VOID_P == 8) || cfg->gen_seq_points_debug_data)
3024                                 no_wrapper = FALSE;
3025                 }
3026         }
3027
3028         if (no_wrapper) {
3029                 char *name;
3030                 int costs;
3031
3032                 if (!info->wrapper_method) {
3033                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3034                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3035                         g_free (name);
3036                         mono_memory_barrier ();
3037                 }
3038
3039                 /*
3040                  * Inline the wrapper method, which is basically a call to the C icall, and
3041                  * an exception check.
3042                  */
3043                 costs = inline_method (cfg, info->wrapper_method, NULL,
3044                                                            args, NULL, cfg->real_offset, TRUE, out_cbb);
3045                 g_assert (costs > 0);
3046                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3047
3048                 return args [0];
3049         } else {
3050                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3051         }
3052 }
3053  
3054 static MonoInst*
3055 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3056 {
3057         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3058                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3059                         int widen_op = -1;
3060
3061                         /* 
3062                          * Native code might return non register sized integers 
3063                          * without initializing the upper bits.
3064                          */
3065                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3066                         case OP_LOADI1_MEMBASE:
3067                                 widen_op = OP_ICONV_TO_I1;
3068                                 break;
3069                         case OP_LOADU1_MEMBASE:
3070                                 widen_op = OP_ICONV_TO_U1;
3071                                 break;
3072                         case OP_LOADI2_MEMBASE:
3073                                 widen_op = OP_ICONV_TO_I2;
3074                                 break;
3075                         case OP_LOADU2_MEMBASE:
3076                                 widen_op = OP_ICONV_TO_U2;
3077                                 break;
3078                         default:
3079                                 break;
3080                         }
3081
3082                         if (widen_op != -1) {
3083                                 int dreg = alloc_preg (cfg);
3084                                 MonoInst *widen;
3085
3086                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3087                                 widen->type = ins->type;
3088                                 ins = widen;
3089                         }
3090                 }
3091         }
3092
3093         return ins;
3094 }
3095
3096 static MonoMethod*
3097 get_memcpy_method (void)
3098 {
3099         static MonoMethod *memcpy_method = NULL;
3100         if (!memcpy_method) {
3101                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3102                 if (!memcpy_method)
3103                         g_error ("Old corlib found. Install a new one");
3104         }
3105         return memcpy_method;
3106 }
3107
3108 static void
3109 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3110 {
3111         MonoClassField *field;
3112         gpointer iter = NULL;
3113
3114         while ((field = mono_class_get_fields (klass, &iter))) {
3115                 int foffset;
3116
3117                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3118                         continue;
3119                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3120                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3121                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3122                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3123                 } else {
3124                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3125                         if (field_class->has_references)
3126                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3127                 }
3128         }
3129 }
3130
3131 static void
3132 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3133 {
3134         int card_table_shift_bits;
3135         gpointer card_table_mask;
3136         guint8 *card_table;
3137         MonoInst *dummy_use;
3138         int nursery_shift_bits;
3139         size_t nursery_size;
3140         gboolean has_card_table_wb = FALSE;
3141
3142         if (!cfg->gen_write_barriers)
3143                 return;
3144
3145         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3146
3147         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3148
3149 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3150         has_card_table_wb = TRUE;
3151 #endif
3152
3153         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3154                 MonoInst *wbarrier;
3155
3156                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3157                 wbarrier->sreg1 = ptr->dreg;
3158                 wbarrier->sreg2 = value->dreg;
3159                 MONO_ADD_INS (cfg->cbb, wbarrier);
3160         } else if (card_table) {
3161                 int offset_reg = alloc_preg (cfg);
3162                 int card_reg  = alloc_preg (cfg);
3163                 MonoInst *ins;
3164
3165                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3166                 if (card_table_mask)
3167                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3168
3169                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3170                  * IMM's larger than 32bits.
3171                  */
3172                 if (cfg->compile_aot) {
3173                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3174                 } else {
3175                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3176                         ins->inst_p0 = card_table;
3177                         ins->dreg = card_reg;
3178                         MONO_ADD_INS (cfg->cbb, ins);
3179                 }
3180
3181                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3182                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3183         } else {
3184                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3185                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3186         }
3187
3188         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3189 }
3190
3191 static gboolean
3192 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3193 {
3194         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3195         unsigned need_wb = 0;
3196
3197         if (align == 0)
3198                 align = 4;
3199
3200         /*types with references can't have alignment smaller than sizeof(void*) */
3201         if (align < SIZEOF_VOID_P)
3202                 return FALSE;
3203
3204         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3205         if (size > 32 * SIZEOF_VOID_P)
3206                 return FALSE;
3207
3208         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3209
3210         /* We don't unroll more than 5 stores to avoid code bloat. */
3211         if (size > 5 * SIZEOF_VOID_P) {
3212                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3213                 size += (SIZEOF_VOID_P - 1);
3214                 size &= ~(SIZEOF_VOID_P - 1);
3215
3216                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3217                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3218                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3219                 return TRUE;
3220         }
3221
3222         destreg = iargs [0]->dreg;
3223         srcreg = iargs [1]->dreg;
3224         offset = 0;
3225
3226         dest_ptr_reg = alloc_preg (cfg);
3227         tmp_reg = alloc_preg (cfg);
3228
3229         /*tmp = dreg*/
3230         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3231
3232         while (size >= SIZEOF_VOID_P) {
3233                 MonoInst *load_inst;
3234                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3235                 load_inst->dreg = tmp_reg;
3236                 load_inst->inst_basereg = srcreg;
3237                 load_inst->inst_offset = offset;
3238                 MONO_ADD_INS (cfg->cbb, load_inst);
3239
3240                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3241
3242                 if (need_wb & 0x1)
3243                         emit_write_barrier (cfg, iargs [0], load_inst);
3244
3245                 offset += SIZEOF_VOID_P;
3246                 size -= SIZEOF_VOID_P;
3247                 need_wb >>= 1;
3248
3249                 /*tmp += sizeof (void*)*/
3250                 if (size >= SIZEOF_VOID_P) {
3251                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3252                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3253                 }
3254         }
3255
3256         /* Those cannot be references since size < sizeof (void*) */
3257         while (size >= 4) {
3258                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3259                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3260                 offset += 4;
3261                 size -= 4;
3262         }
3263
3264         while (size >= 2) {
3265                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3266                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3267                 offset += 2;
3268                 size -= 2;
3269         }
3270
3271         while (size >= 1) {
3272                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3273                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3274                 offset += 1;
3275                 size -= 1;
3276         }
3277
3278         return TRUE;
3279 }
3280
3281 /*
3282  * Emit code to copy a valuetype of type @klass whose address is stored in
3283  * @src->dreg to memory whose address is stored at @dest->dreg.
3284  */
3285 void
3286 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3287 {
3288         MonoInst *iargs [4];
3289         int n;
3290         guint32 align = 0;
3291         MonoMethod *memcpy_method;
3292         MonoInst *size_ins = NULL;
3293         MonoInst *memcpy_ins = NULL;
3294
3295         g_assert (klass);
3296         if (cfg->generic_sharing_context)
3297                 klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &klass->byval_arg));
3298
3299         /*
3300          * This check breaks with spilled vars... need to handle it during verification anyway.
3301          * g_assert (klass && klass == src->klass && klass == dest->klass);
3302          */
3303
3304         if (mini_is_gsharedvt_klass (cfg, klass)) {
3305                 g_assert (!native);
3306                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3307                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3308         }
3309
3310         if (native)
3311                 n = mono_class_native_size (klass, &align);
3312         else
3313                 n = mono_class_value_size (klass, &align);
3314
3315         /* if native is true there should be no references in the struct */
3316         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3317                 /* Avoid barriers when storing to the stack */
3318                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3319                           (dest->opcode == OP_LDADDR))) {
3320                         int context_used;
3321
3322                         iargs [0] = dest;
3323                         iargs [1] = src;
3324
3325                         context_used = mini_class_check_context_used (cfg, klass);
3326
3327                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3328                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3329                                 return;
3330                         } else if (context_used) {
3331                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3332                         }  else {
3333                                 if (cfg->compile_aot) {
3334                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3335                                 } else {
3336                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3337                                         mono_class_compute_gc_descriptor (klass);
3338                                 }
3339                         }
3340
3341                         if (size_ins)
3342                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3343                         else
3344                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3345                         return;
3346                 }
3347         }
3348
3349         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3350                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3351                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3352         } else {
3353                 iargs [0] = dest;
3354                 iargs [1] = src;
3355                 if (size_ins)
3356                         iargs [2] = size_ins;
3357                 else
3358                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3359                 
3360                 memcpy_method = get_memcpy_method ();
3361                 if (memcpy_ins)
3362                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3363                 else
3364                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3365         }
3366 }
3367
3368 static MonoMethod*
3369 get_memset_method (void)
3370 {
3371         static MonoMethod *memset_method = NULL;
3372         if (!memset_method) {
3373                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3374                 if (!memset_method)
3375                         g_error ("Old corlib found. Install a new one");
3376         }
3377         return memset_method;
3378 }
3379
3380 void
3381 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3382 {
3383         MonoInst *iargs [3];
3384         int n;
3385         guint32 align;
3386         MonoMethod *memset_method;
3387         MonoInst *size_ins = NULL;
3388         MonoInst *bzero_ins = NULL;
3389         static MonoMethod *bzero_method;
3390
3391         /* FIXME: Optimize this for the case when dest is an LDADDR */
3392         mono_class_init (klass);
3393         if (mini_is_gsharedvt_klass (cfg, klass)) {
3394                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3395                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3396                 if (!bzero_method)
3397                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3398                 g_assert (bzero_method);
3399                 iargs [0] = dest;
3400                 iargs [1] = size_ins;
3401                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3402                 return;
3403         }
3404
3405         n = mono_class_value_size (klass, &align);
3406
3407         if (n <= sizeof (gpointer) * 8) {
3408                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3409         }
3410         else {
3411                 memset_method = get_memset_method ();
3412                 iargs [0] = dest;
3413                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3414                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3415                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3416         }
3417 }
3418
3419 static MonoInst*
3420 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3421 {
3422         MonoInst *this = NULL;
3423
3424         g_assert (cfg->generic_sharing_context);
3425
3426         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3427                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3428                         !method->klass->valuetype)
3429                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3430
3431         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3432                 MonoInst *mrgctx_loc, *mrgctx_var;
3433
3434                 g_assert (!this);
3435                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3436
3437                 mrgctx_loc = mono_get_vtable_var (cfg);
3438                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3439
3440                 return mrgctx_var;
3441         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3442                 MonoInst *vtable_loc, *vtable_var;
3443
3444                 g_assert (!this);
3445
3446                 vtable_loc = mono_get_vtable_var (cfg);
3447                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3448
3449                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3450                         MonoInst *mrgctx_var = vtable_var;
3451                         int vtable_reg;
3452
3453                         vtable_reg = alloc_preg (cfg);
3454                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3455                         vtable_var->type = STACK_PTR;
3456                 }
3457
3458                 return vtable_var;
3459         } else {
3460                 MonoInst *ins;
3461                 int vtable_reg;
3462         
3463                 vtable_reg = alloc_preg (cfg);
3464                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3465                 return ins;
3466         }
3467 }
3468
3469 static MonoJumpInfoRgctxEntry *
3470 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3471 {
3472         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3473         res->method = method;
3474         res->in_mrgctx = in_mrgctx;
3475         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3476         res->data->type = patch_type;
3477         res->data->data.target = patch_data;
3478         res->info_type = info_type;
3479
3480         return res;
3481 }
3482
3483 static inline MonoInst*
3484 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3485 {
3486         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3487 }
3488
3489 static MonoInst*
3490 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3491                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3492 {
3493         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);
3494         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3495
3496         return emit_rgctx_fetch (cfg, rgctx, entry);
3497 }
3498
3499 static MonoInst*
3500 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3501                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3502 {
3503         MonoJumpInfoRgctxEntry *entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_SIGNATURE, sig, rgctx_type);
3504         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3505
3506         return emit_rgctx_fetch (cfg, rgctx, entry);
3507 }
3508
3509 static MonoInst*
3510 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3511                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3512 {
3513         MonoJumpInfoGSharedVtCall *call_info;
3514         MonoJumpInfoRgctxEntry *entry;
3515         MonoInst *rgctx;
3516
3517         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3518         call_info->sig = sig;
3519         call_info->method = cmethod;
3520
3521         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_CALL, call_info, rgctx_type);
3522         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3523
3524         return emit_rgctx_fetch (cfg, rgctx, entry);
3525 }
3526
3527
3528 static MonoInst*
3529 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3530                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3531 {
3532         MonoJumpInfoRgctxEntry *entry;
3533         MonoInst *rgctx;
3534
3535         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_GSHAREDVT_METHOD, info, MONO_RGCTX_INFO_METHOD_GSHAREDVT_INFO);
3536         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3537
3538         return emit_rgctx_fetch (cfg, rgctx, entry);
3539 }
3540
3541 /*
3542  * emit_get_rgctx_method:
3543  *
3544  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3545  * normal constants, else emit a load from the rgctx.
3546  */
3547 static MonoInst*
3548 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3549                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3550 {
3551         if (!context_used) {
3552                 MonoInst *ins;
3553
3554                 switch (rgctx_type) {
3555                 case MONO_RGCTX_INFO_METHOD:
3556                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3557                         return ins;
3558                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3559                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3560                         return ins;
3561                 default:
3562                         g_assert_not_reached ();
3563                 }
3564         } else {
3565                 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);
3566                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3567
3568                 return emit_rgctx_fetch (cfg, rgctx, entry);
3569         }
3570 }
3571
3572 static MonoInst*
3573 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3574                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3575 {
3576         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);
3577         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3578
3579         return emit_rgctx_fetch (cfg, rgctx, entry);
3580 }
3581
3582 static int
3583 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3584 {
3585         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3586         MonoRuntimeGenericContextInfoTemplate *template;
3587         int i, idx;
3588
3589         g_assert (info);
3590
3591         for (i = 0; i < info->num_entries; ++i) {
3592                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3593
3594                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3595                         return i;
3596         }
3597
3598         if (info->num_entries == info->count_entries) {
3599                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3600                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3601
3602                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3603
3604                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3605                 info->entries = new_entries;
3606                 info->count_entries = new_count_entries;
3607         }
3608
3609         idx = info->num_entries;
3610         template = &info->entries [idx];
3611         template->info_type = rgctx_type;
3612         template->data = data;
3613
3614         info->num_entries ++;
3615
3616         return idx;
3617 }
3618
3619 /*
3620  * emit_get_gsharedvt_info:
3621  *
3622  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3623  */
3624 static MonoInst*
3625 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3626 {
3627         MonoInst *ins;
3628         int idx, dreg;
3629
3630         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3631         /* Load info->entries [idx] */
3632         dreg = alloc_preg (cfg);
3633         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3634
3635         return ins;
3636 }
3637
3638 static MonoInst*
3639 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3640 {
3641         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3642 }
3643
3644 /*
3645  * On return the caller must check @klass for load errors.
3646  */
3647 static void
3648 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3649 {
3650         MonoInst *vtable_arg;
3651         MonoCallInst *call;
3652         int context_used;
3653
3654         context_used = mini_class_check_context_used (cfg, klass);
3655
3656         if (context_used) {
3657                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3658                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3659         } else {
3660                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3661
3662                 if (!vtable)
3663                         return;
3664                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3665         }
3666
3667         if (COMPILE_LLVM (cfg))
3668                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3669         else
3670                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3671 #ifdef MONO_ARCH_VTABLE_REG
3672         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3673         cfg->uses_vtable_reg = TRUE;
3674 #else
3675         NOT_IMPLEMENTED;
3676 #endif
3677 }
3678
3679 static void
3680 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3681 {
3682         MonoInst *ins;
3683
3684         if (cfg->gen_seq_points && cfg->method == method) {
3685                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3686                 if (nonempty_stack)
3687                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3688                 MONO_ADD_INS (cfg->cbb, ins);
3689         }
3690 }
3691
3692 static void
3693 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3694 {
3695         if (mini_get_debug_options ()->better_cast_details) {
3696                 int vtable_reg = alloc_preg (cfg);
3697                 int klass_reg = alloc_preg (cfg);
3698                 MonoBasicBlock *is_null_bb = NULL;
3699                 MonoInst *tls_get;
3700                 int to_klass_reg, context_used;
3701
3702                 if (null_check) {
3703                         NEW_BBLOCK (cfg, is_null_bb);
3704
3705                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3706                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3707                 }
3708
3709                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3710                 if (!tls_get) {
3711                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3712                         exit (1);
3713                 }
3714
3715                 MONO_ADD_INS (cfg->cbb, tls_get);
3716                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3717                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3718
3719                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3720
3721                 context_used = mini_class_check_context_used (cfg, klass);
3722                 if (context_used) {
3723                         MonoInst *class_ins;
3724
3725                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3726                         to_klass_reg = class_ins->dreg;
3727                 } else {
3728                         to_klass_reg = alloc_preg (cfg);
3729                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3730                 }
3731                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3732
3733                 if (null_check) {
3734                         MONO_START_BB (cfg, is_null_bb);
3735                         if (out_bblock)
3736                                 *out_bblock = cfg->cbb;
3737                 }
3738         }
3739 }
3740
3741 static void
3742 reset_cast_details (MonoCompile *cfg)
3743 {
3744         /* Reset the variables holding the cast details */
3745         if (mini_get_debug_options ()->better_cast_details) {
3746                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3747
3748                 MONO_ADD_INS (cfg->cbb, tls_get);
3749                 /* It is enough to reset the from field */
3750                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3751         }
3752 }
3753
3754 /*
3755  * On return the caller must check @array_class for load errors
3756  */
3757 static void
3758 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3759 {
3760         int vtable_reg = alloc_preg (cfg);
3761         int context_used;
3762
3763         context_used = mini_class_check_context_used (cfg, array_class);
3764
3765         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3766
3767         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3768
3769         if (cfg->opt & MONO_OPT_SHARED) {
3770                 int class_reg = alloc_preg (cfg);
3771                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3772                 if (cfg->compile_aot) {
3773                         int klass_reg = alloc_preg (cfg);
3774                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3775                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3776                 } else {
3777                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3778                 }
3779         } else if (context_used) {
3780                 MonoInst *vtable_ins;
3781
3782                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3783                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3784         } else {
3785                 if (cfg->compile_aot) {
3786                         int vt_reg;
3787                         MonoVTable *vtable;
3788
3789                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3790                                 return;
3791                         vt_reg = alloc_preg (cfg);
3792                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3793                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3794                 } else {
3795                         MonoVTable *vtable;
3796                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3797                                 return;
3798                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3799                 }
3800         }
3801         
3802         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3803
3804         reset_cast_details (cfg);
3805 }
3806
3807 /**
3808  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3809  * generic code is generated.
3810  */
3811 static MonoInst*
3812 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3813 {
3814         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3815
3816         if (context_used) {
3817                 MonoInst *rgctx, *addr;
3818
3819                 /* FIXME: What if the class is shared?  We might not
3820                    have to get the address of the method from the
3821                    RGCTX. */
3822                 addr = emit_get_rgctx_method (cfg, context_used, method,
3823                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3824
3825                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3826
3827                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3828         } else {
3829                 gboolean pass_vtable, pass_mrgctx;
3830                 MonoInst *rgctx_arg = NULL;
3831
3832                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3833                 g_assert (!pass_mrgctx);
3834
3835                 if (pass_vtable) {
3836                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3837
3838                         g_assert (vtable);
3839                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3840                 }
3841
3842                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3843         }
3844 }
3845
3846 static MonoInst*
3847 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3848 {
3849         MonoInst *add;
3850         int obj_reg;
3851         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3852         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3853         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3854         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3855
3856         obj_reg = sp [0]->dreg;
3857         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3858         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3859
3860         /* FIXME: generics */
3861         g_assert (klass->rank == 0);
3862                         
3863         // Check rank == 0
3864         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3865         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3866
3867         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3868         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3869
3870         if (context_used) {
3871                 MonoInst *element_class;
3872
3873                 /* This assertion is from the unboxcast insn */
3874                 g_assert (klass->rank == 0);
3875
3876                 element_class = emit_get_rgctx_klass (cfg, context_used,
3877                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3878
3879                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3880                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3881         } else {
3882                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3883                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3884                 reset_cast_details (cfg);
3885         }
3886
3887         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3888         MONO_ADD_INS (cfg->cbb, add);
3889         add->type = STACK_MP;
3890         add->klass = klass;
3891
3892         return add;
3893 }
3894
3895 static MonoInst*
3896 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3897 {
3898         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3899         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3900         MonoInst *ins;
3901         int dreg, addr_reg;
3902
3903         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3904
3905         /* obj */
3906         args [0] = obj;
3907
3908         /* klass */
3909         args [1] = klass_inst;
3910
3911         /* CASTCLASS */
3912         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3913
3914         NEW_BBLOCK (cfg, is_ref_bb);
3915         NEW_BBLOCK (cfg, is_nullable_bb);
3916         NEW_BBLOCK (cfg, end_bb);
3917         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3918         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3919         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3920
3921         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3922         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3923
3924         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3925         addr_reg = alloc_dreg (cfg, STACK_MP);
3926
3927         /* Non-ref case */
3928         /* UNBOX */
3929         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3930         MONO_ADD_INS (cfg->cbb, addr);
3931
3932         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3933
3934         /* Ref case */
3935         MONO_START_BB (cfg, is_ref_bb);
3936
3937         /* Save the ref to a temporary */
3938         dreg = alloc_ireg (cfg);
3939         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3940         addr->dreg = addr_reg;
3941         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3942         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3943
3944         /* Nullable case */
3945         MONO_START_BB (cfg, is_nullable_bb);
3946
3947         {
3948                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3949                 MonoInst *unbox_call;
3950                 MonoMethodSignature *unbox_sig;
3951
3952                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3953                 unbox_sig->ret = &klass->byval_arg;
3954                 unbox_sig->param_count = 1;
3955                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3956                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3957
3958                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3959                 addr->dreg = addr_reg;
3960         }
3961
3962         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3963
3964         /* End */
3965         MONO_START_BB (cfg, end_bb);
3966
3967         /* LDOBJ */
3968         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3969
3970         *out_cbb = cfg->cbb;
3971
3972         return ins;
3973 }
3974
3975 /*
3976  * Returns NULL and set the cfg exception on error.
3977  */
3978 static MonoInst*
3979 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3980 {
3981         MonoInst *iargs [2];
3982         void *alloc_ftn;
3983
3984         if (context_used) {
3985                 MonoInst *data;
3986                 int rgctx_info;
3987                 MonoInst *iargs [2];
3988                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3989
3990                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3991
3992                 if (cfg->opt & MONO_OPT_SHARED)
3993                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3994                 else
3995                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3996                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3997
3998                 if (cfg->opt & MONO_OPT_SHARED) {
3999                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4000                         iargs [1] = data;
4001                         alloc_ftn = mono_object_new;
4002                 } else {
4003                         iargs [0] = data;
4004                         alloc_ftn = mono_object_new_specific;
4005                 }
4006
4007                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4008                         if (known_instance_size)
4009                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4010                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4011                 }
4012
4013                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4014         }
4015
4016         if (cfg->opt & MONO_OPT_SHARED) {
4017                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4018                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4019
4020                 alloc_ftn = mono_object_new;
4021         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4022                 /* This happens often in argument checking code, eg. throw new FooException... */
4023                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4024                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4025                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4026         } else {
4027                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4028                 MonoMethod *managed_alloc = NULL;
4029                 gboolean pass_lw;
4030
4031                 if (!vtable) {
4032                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4033                         cfg->exception_ptr = klass;
4034                         return NULL;
4035                 }
4036
4037 #ifndef MONO_CROSS_COMPILE
4038                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4039 #endif
4040
4041                 if (managed_alloc) {
4042                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4043                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4044                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4045                 }
4046                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4047                 if (pass_lw) {
4048                         guint32 lw = vtable->klass->instance_size;
4049                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4050                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4051                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4052                 }
4053                 else {
4054                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4055                 }
4056         }
4057
4058         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4059 }
4060         
4061 /*
4062  * Returns NULL and set the cfg exception on error.
4063  */     
4064 static MonoInst*
4065 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
4066 {
4067         MonoInst *alloc, *ins;
4068
4069         *out_cbb = cfg->cbb;
4070
4071         if (mono_class_is_nullable (klass)) {
4072                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4073
4074                 if (context_used) {
4075                         /* FIXME: What if the class is shared?  We might not
4076                            have to get the method address from the RGCTX. */
4077                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4078                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4079                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4080
4081                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4082                 } else {
4083                         gboolean pass_vtable, pass_mrgctx;
4084                         MonoInst *rgctx_arg = NULL;
4085
4086                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4087                         g_assert (!pass_mrgctx);
4088
4089                         if (pass_vtable) {
4090                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4091
4092                                 g_assert (vtable);
4093                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4094                         }
4095
4096                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4097                 }
4098         }
4099
4100         if (mini_is_gsharedvt_klass (cfg, klass)) {
4101                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4102                 MonoInst *res, *is_ref, *src_var, *addr;
4103                 int dreg;
4104
4105                 dreg = alloc_ireg (cfg);
4106
4107                 NEW_BBLOCK (cfg, is_ref_bb);
4108                 NEW_BBLOCK (cfg, is_nullable_bb);
4109                 NEW_BBLOCK (cfg, end_bb);
4110                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4111                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4112                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4113
4114                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4115                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4116
4117                 /* Non-ref case */
4118                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4119                 if (!alloc)
4120                         return NULL;
4121                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4122                 ins->opcode = OP_STOREV_MEMBASE;
4123
4124                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4125                 res->type = STACK_OBJ;
4126                 res->klass = klass;
4127                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4128                 
4129                 /* Ref case */
4130                 MONO_START_BB (cfg, is_ref_bb);
4131
4132                 /* val is a vtype, so has to load the value manually */
4133                 src_var = get_vreg_to_inst (cfg, val->dreg);
4134                 if (!src_var)
4135                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4136                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4137                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4138                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4139
4140                 /* Nullable case */
4141                 MONO_START_BB (cfg, is_nullable_bb);
4142
4143                 {
4144                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4145                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4146                         MonoInst *box_call;
4147                         MonoMethodSignature *box_sig;
4148
4149                         /*
4150                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4151                          * construct that method at JIT time, so have to do things by hand.
4152                          */
4153                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4154                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4155                         box_sig->param_count = 1;
4156                         box_sig->params [0] = &klass->byval_arg;
4157                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4158                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4159                         res->type = STACK_OBJ;
4160                         res->klass = klass;
4161                 }
4162
4163                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4164
4165                 MONO_START_BB (cfg, end_bb);
4166
4167                 *out_cbb = cfg->cbb;
4168
4169                 return res;
4170         } else {
4171                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4172                 if (!alloc)
4173                         return NULL;
4174
4175                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4176                 return alloc;
4177         }
4178 }
4179
4180
4181 static gboolean
4182 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4183 {
4184         int i;
4185         MonoGenericContainer *container;
4186         MonoGenericInst *ginst;
4187
4188         if (klass->generic_class) {
4189                 container = klass->generic_class->container_class->generic_container;
4190                 ginst = klass->generic_class->context.class_inst;
4191         } else if (klass->generic_container && context_used) {
4192                 container = klass->generic_container;
4193                 ginst = container->context.class_inst;
4194         } else {
4195                 return FALSE;
4196         }
4197
4198         for (i = 0; i < container->type_argc; ++i) {
4199                 MonoType *type;
4200                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4201                         continue;
4202                 type = ginst->type_argv [i];
4203                 if (mini_type_is_reference (cfg, type))
4204                         return TRUE;
4205         }
4206         return FALSE;
4207 }
4208
4209 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4210
4211 static MonoInst*
4212 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4213 {
4214         MonoMethod *mono_castclass;
4215         MonoInst *res;
4216
4217         mono_castclass = mono_marshal_get_castclass_with_cache ();
4218
4219         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4220         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4221         reset_cast_details (cfg);
4222         *out_bblock = cfg->cbb;
4223
4224         return res;
4225 }
4226
4227 static MonoInst*
4228 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4229 {
4230         MonoInst *args [3];
4231         int idx;
4232
4233         /* obj */
4234         args [0] = obj;
4235
4236         /* klass */
4237         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4238
4239         /* inline cache*/
4240         if (cfg->compile_aot) {
4241                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4242                 cfg->castclass_cache_index ++;
4243                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4244                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4245         } else {
4246                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4247         }
4248
4249         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4250
4251         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4252 }
4253
4254 /*
4255  * Returns NULL and set the cfg exception on error.
4256  */
4257 static MonoInst*
4258 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4259 {
4260         MonoBasicBlock *is_null_bb;
4261         int obj_reg = src->dreg;
4262         int vtable_reg = alloc_preg (cfg);
4263         int context_used;
4264         MonoInst *klass_inst = NULL, *res;
4265         MonoBasicBlock *bblock;
4266
4267         *out_bb = cfg->cbb;
4268
4269         context_used = mini_class_check_context_used (cfg, klass);
4270
4271         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4272                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4273                 (*inline_costs) += 2;
4274                 *out_bb = cfg->cbb;
4275                 return res;
4276         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4277                 MonoMethod *mono_castclass;
4278                 MonoInst *iargs [1];
4279                 int costs;
4280
4281                 mono_castclass = mono_marshal_get_castclass (klass); 
4282                 iargs [0] = src;
4283                                 
4284                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4285                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4286                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4287                 reset_cast_details (cfg);
4288                 CHECK_CFG_EXCEPTION;
4289                 g_assert (costs > 0);
4290                                 
4291                 cfg->real_offset += 5;
4292
4293                 (*inline_costs) += costs;
4294
4295                 *out_bb = cfg->cbb;
4296                 return src;
4297         }
4298
4299         if (context_used) {
4300                 MonoInst *args [3];
4301
4302                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4303                         MonoInst *cache_ins;
4304
4305                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4306
4307                         /* obj */
4308                         args [0] = src;
4309
4310                         /* klass - it's the second element of the cache entry*/
4311                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4312
4313                         /* cache */
4314                         args [2] = cache_ins;
4315
4316                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4317                 }
4318
4319                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4320         }
4321
4322         NEW_BBLOCK (cfg, is_null_bb);
4323
4324         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4325         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4326
4327         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4328
4329         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4330                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4331                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4332         } else {
4333                 int klass_reg = alloc_preg (cfg);
4334
4335                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4336
4337                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4338                         /* the remoting code is broken, access the class for now */
4339                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4340                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4341                                 if (!vt) {
4342                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4343                                         cfg->exception_ptr = klass;
4344                                         return NULL;
4345                                 }
4346                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4347                         } else {
4348                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4349                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4350                         }
4351                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4352                 } else {
4353                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4354                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4355                 }
4356         }
4357
4358         MONO_START_BB (cfg, is_null_bb);
4359
4360         reset_cast_details (cfg);
4361
4362         *out_bb = cfg->cbb;
4363
4364         return src;
4365
4366 exception_exit:
4367         return NULL;
4368 }
4369
4370 /*
4371  * Returns NULL and set the cfg exception on error.
4372  */
4373 static MonoInst*
4374 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4375 {
4376         MonoInst *ins;
4377         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4378         int obj_reg = src->dreg;
4379         int vtable_reg = alloc_preg (cfg);
4380         int res_reg = alloc_ireg_ref (cfg);
4381         MonoInst *klass_inst = NULL;
4382
4383         if (context_used) {
4384                 MonoInst *args [3];
4385
4386                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4387                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4388                         MonoInst *cache_ins;
4389
4390                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4391
4392                         /* obj */
4393                         args [0] = src;
4394
4395                         /* klass - it's the second element of the cache entry*/
4396                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4397
4398                         /* cache */
4399                         args [2] = cache_ins;
4400
4401                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4402                 }
4403
4404                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4405         }
4406
4407         NEW_BBLOCK (cfg, is_null_bb);
4408         NEW_BBLOCK (cfg, false_bb);
4409         NEW_BBLOCK (cfg, end_bb);
4410
4411         /* Do the assignment at the beginning, so the other assignment can be if converted */
4412         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4413         ins->type = STACK_OBJ;
4414         ins->klass = klass;
4415
4416         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4417         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4418
4419         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4420
4421         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4422                 g_assert (!context_used);
4423                 /* the is_null_bb target simply copies the input register to the output */
4424                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4425         } else {
4426                 int klass_reg = alloc_preg (cfg);
4427
4428                 if (klass->rank) {
4429                         int rank_reg = alloc_preg (cfg);
4430                         int eclass_reg = alloc_preg (cfg);
4431
4432                         g_assert (!context_used);
4433                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4434                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4435                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4436                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4437                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4438                         if (klass->cast_class == mono_defaults.object_class) {
4439                                 int parent_reg = alloc_preg (cfg);
4440                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4441                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4442                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4443                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4444                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4445                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4446                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4447                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4448                         } else if (klass->cast_class == mono_defaults.enum_class) {
4449                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4450                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4451                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4452                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4453                         } else {
4454                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4455                                         /* Check that the object is a vector too */
4456                                         int bounds_reg = alloc_preg (cfg);
4457                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4458                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4459                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4460                                 }
4461
4462                                 /* the is_null_bb target simply copies the input register to the output */
4463                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4464                         }
4465                 } else if (mono_class_is_nullable (klass)) {
4466                         g_assert (!context_used);
4467                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4468                         /* the is_null_bb target simply copies the input register to the output */
4469                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4470                 } else {
4471                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4472                                 g_assert (!context_used);
4473                                 /* the remoting code is broken, access the class for now */
4474                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4475                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4476                                         if (!vt) {
4477                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4478                                                 cfg->exception_ptr = klass;
4479                                                 return NULL;
4480                                         }
4481                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4482                                 } else {
4483                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4484                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4485                                 }
4486                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4487                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4488                         } else {
4489                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4490                                 /* the is_null_bb target simply copies the input register to the output */
4491                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4492                         }
4493                 }
4494         }
4495
4496         MONO_START_BB (cfg, false_bb);
4497
4498         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4499         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4500
4501         MONO_START_BB (cfg, is_null_bb);
4502
4503         MONO_START_BB (cfg, end_bb);
4504
4505         return ins;
4506 }
4507
4508 static MonoInst*
4509 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4510 {
4511         /* This opcode takes as input an object reference and a class, and returns:
4512         0) if the object is an instance of the class,
4513         1) if the object is not instance of the class,
4514         2) if the object is a proxy whose type cannot be determined */
4515
4516         MonoInst *ins;
4517 #ifndef DISABLE_REMOTING
4518         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4519 #else
4520         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4521 #endif
4522         int obj_reg = src->dreg;
4523         int dreg = alloc_ireg (cfg);
4524         int tmp_reg;
4525 #ifndef DISABLE_REMOTING
4526         int klass_reg = alloc_preg (cfg);
4527 #endif
4528
4529         NEW_BBLOCK (cfg, true_bb);
4530         NEW_BBLOCK (cfg, false_bb);
4531         NEW_BBLOCK (cfg, end_bb);
4532 #ifndef DISABLE_REMOTING
4533         NEW_BBLOCK (cfg, false2_bb);
4534         NEW_BBLOCK (cfg, no_proxy_bb);
4535 #endif
4536
4537         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4538         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4539
4540         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4541 #ifndef DISABLE_REMOTING
4542                 NEW_BBLOCK (cfg, interface_fail_bb);
4543 #endif
4544
4545                 tmp_reg = alloc_preg (cfg);
4546                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4547 #ifndef DISABLE_REMOTING
4548                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4549                 MONO_START_BB (cfg, interface_fail_bb);
4550                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4551                 
4552                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4553
4554                 tmp_reg = alloc_preg (cfg);
4555                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4556                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4557                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4558 #else
4559                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4560 #endif
4561         } else {
4562 #ifndef DISABLE_REMOTING
4563                 tmp_reg = alloc_preg (cfg);
4564                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4565                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4566
4567                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4568                 tmp_reg = alloc_preg (cfg);
4569                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4570                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4571
4572                 tmp_reg = alloc_preg (cfg);             
4573                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4574                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4575                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4576                 
4577                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4578                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4579
4580                 MONO_START_BB (cfg, no_proxy_bb);
4581
4582                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4583 #else
4584                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4585 #endif
4586         }
4587
4588         MONO_START_BB (cfg, false_bb);
4589
4590         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4591         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4592
4593 #ifndef DISABLE_REMOTING
4594         MONO_START_BB (cfg, false2_bb);
4595
4596         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4597         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4598 #endif
4599
4600         MONO_START_BB (cfg, true_bb);
4601
4602         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4603
4604         MONO_START_BB (cfg, end_bb);
4605
4606         /* FIXME: */
4607         MONO_INST_NEW (cfg, ins, OP_ICONST);
4608         ins->dreg = dreg;
4609         ins->type = STACK_I4;
4610
4611         return ins;
4612 }
4613
4614 static MonoInst*
4615 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4616 {
4617         /* This opcode takes as input an object reference and a class, and returns:
4618         0) if the object is an instance of the class,
4619         1) if the object is a proxy whose type cannot be determined
4620         an InvalidCastException exception is thrown otherwhise*/
4621         
4622         MonoInst *ins;
4623 #ifndef DISABLE_REMOTING
4624         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4625 #else
4626         MonoBasicBlock *ok_result_bb;
4627 #endif
4628         int obj_reg = src->dreg;
4629         int dreg = alloc_ireg (cfg);
4630         int tmp_reg = alloc_preg (cfg);
4631
4632 #ifndef DISABLE_REMOTING
4633         int klass_reg = alloc_preg (cfg);
4634         NEW_BBLOCK (cfg, end_bb);
4635 #endif
4636
4637         NEW_BBLOCK (cfg, ok_result_bb);
4638
4639         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4640         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4641
4642         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4643
4644         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4645 #ifndef DISABLE_REMOTING
4646                 NEW_BBLOCK (cfg, interface_fail_bb);
4647         
4648                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4649                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4650                 MONO_START_BB (cfg, interface_fail_bb);
4651                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4652
4653                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4654
4655                 tmp_reg = alloc_preg (cfg);             
4656                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4657                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4658                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4659                 
4660                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4661                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4662 #else
4663                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4664                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4665                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4666 #endif
4667         } else {
4668 #ifndef DISABLE_REMOTING
4669                 NEW_BBLOCK (cfg, no_proxy_bb);
4670
4671                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4672                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4673                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4674
4675                 tmp_reg = alloc_preg (cfg);
4676                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4677                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4678
4679                 tmp_reg = alloc_preg (cfg);
4680                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4681                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4682                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4683
4684                 NEW_BBLOCK (cfg, fail_1_bb);
4685                 
4686                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4687
4688                 MONO_START_BB (cfg, fail_1_bb);
4689
4690                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4691                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4692
4693                 MONO_START_BB (cfg, no_proxy_bb);
4694
4695                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4696 #else
4697                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4698 #endif
4699         }
4700
4701         MONO_START_BB (cfg, ok_result_bb);
4702
4703         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4704
4705 #ifndef DISABLE_REMOTING
4706         MONO_START_BB (cfg, end_bb);
4707 #endif
4708
4709         /* FIXME: */
4710         MONO_INST_NEW (cfg, ins, OP_ICONST);
4711         ins->dreg = dreg;
4712         ins->type = STACK_I4;
4713
4714         return ins;
4715 }
4716
4717 static G_GNUC_UNUSED MonoInst*
4718 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4719 {
4720         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4721         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4722         gboolean is_i4;
4723
4724         switch (enum_type->type) {
4725         case MONO_TYPE_I8:
4726         case MONO_TYPE_U8:
4727 #if SIZEOF_REGISTER == 8
4728         case MONO_TYPE_I:
4729         case MONO_TYPE_U:
4730 #endif
4731                 is_i4 = FALSE;
4732                 break;
4733         default:
4734                 is_i4 = TRUE;
4735                 break;
4736         }
4737
4738         {
4739                 MonoInst *load, *and, *cmp, *ceq;
4740                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4741                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4742                 int dest_reg = alloc_ireg (cfg);
4743
4744                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4745                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4746                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4747                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4748
4749                 ceq->type = STACK_I4;
4750
4751                 if (!is_i4) {
4752                         load = mono_decompose_opcode (cfg, load, NULL);
4753                         and = mono_decompose_opcode (cfg, and, NULL);
4754                         cmp = mono_decompose_opcode (cfg, cmp, NULL);
4755                         ceq = mono_decompose_opcode (cfg, ceq, NULL);
4756                 }
4757
4758                 return ceq;
4759         }
4760 }
4761
4762 /*
4763  * Returns NULL and set the cfg exception on error.
4764  */
4765 static G_GNUC_UNUSED MonoInst*
4766 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4767 {
4768         MonoInst *ptr;
4769         int dreg;
4770         gpointer trampoline;
4771         MonoInst *obj, *method_ins, *tramp_ins;
4772         MonoDomain *domain;
4773         guint8 **code_slot;
4774         
4775         // FIXME reenable optimisation for virtual case
4776         if (virtual)
4777                 return NULL;
4778
4779         if (virtual) {
4780                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4781                 g_assert (invoke);
4782
4783                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4784                         return NULL;
4785         }
4786
4787         obj = handle_alloc (cfg, klass, FALSE, 0);
4788         if (!obj)
4789                 return NULL;
4790
4791         /* Inline the contents of mono_delegate_ctor */
4792
4793         /* Set target field */
4794         /* Optimize away setting of NULL target */
4795         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4796                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4797                 if (cfg->gen_write_barriers) {
4798                         dreg = alloc_preg (cfg);
4799                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4800                         emit_write_barrier (cfg, ptr, target);
4801                 }
4802         }
4803
4804         /* Set method field */
4805         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4806         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4807
4808         /* 
4809          * To avoid looking up the compiled code belonging to the target method
4810          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4811          * store it, and we fill it after the method has been compiled.
4812          */
4813         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4814                 MonoInst *code_slot_ins;
4815
4816                 if (context_used) {
4817                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4818                 } else {
4819                         domain = mono_domain_get ();
4820                         mono_domain_lock (domain);
4821                         if (!domain_jit_info (domain)->method_code_hash)
4822                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4823                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4824                         if (!code_slot) {
4825                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4826                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4827                         }
4828                         mono_domain_unlock (domain);
4829
4830                         if (cfg->compile_aot)
4831                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4832                         else
4833                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4834                 }
4835                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4836         }
4837
4838         if (cfg->compile_aot) {
4839                 MonoDelegateClassMethodPair *del_tramp;
4840
4841                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4842                 del_tramp->klass = klass;
4843                 del_tramp->method = context_used ? NULL : method;
4844                 del_tramp->virtual = virtual;
4845                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4846         } else {
4847                 if (virtual)
4848                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4849                 else
4850                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4851                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4852         }
4853
4854         /* Set invoke_impl field */
4855         if (virtual) {
4856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4857         } else {
4858                 dreg = alloc_preg (cfg);
4859                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4860                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4861
4862                 dreg = alloc_preg (cfg);
4863                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4864                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4865         }
4866
4867         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4868
4869         return obj;
4870 }
4871
4872 static MonoInst*
4873 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4874 {
4875         MonoJitICallInfo *info;
4876
4877         /* Need to register the icall so it gets an icall wrapper */
4878         info = mono_get_array_new_va_icall (rank);
4879
4880         cfg->flags |= MONO_CFG_HAS_VARARGS;
4881
4882         /* mono_array_new_va () needs a vararg calling convention */
4883         cfg->disable_llvm = TRUE;
4884
4885         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4886         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4887 }
4888
4889 /*
4890  * handle_constrained_gsharedvt_call:
4891  *
4892  *   Handle constrained calls where the receiver is a gsharedvt type.
4893  * Return the instruction representing the call. Set the cfg exception on failure.
4894  */
4895 static MonoInst*
4896 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4897                                                                    gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
4898 {
4899         MonoInst *ins = NULL;
4900         MonoBasicBlock *bblock = *ref_bblock;
4901         gboolean emit_widen = *ref_emit_widen;
4902
4903         /*
4904          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4905          * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
4906          * pack the arguments into an array, and do the rest of the work in in an icall.
4907          */
4908         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4909                 (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret) || mini_is_gsharedvt_type (cfg, fsig->ret)) &&
4910                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
4911                 MonoInst *args [16];
4912
4913                 /*
4914                  * This case handles calls to
4915                  * - object:ToString()/Equals()/GetHashCode(),
4916                  * - System.IComparable<T>:CompareTo()
4917                  * - System.IEquatable<T>:Equals ()
4918                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4919                  */
4920
4921                 args [0] = sp [0];
4922                 if (mono_method_check_context_used (cmethod))
4923                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4924                 else
4925                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4926                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4927
4928                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4929                 if (fsig->hasthis && fsig->param_count) {
4930                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4931                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4932                         ins->dreg = alloc_preg (cfg);
4933                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4934                         MONO_ADD_INS (cfg->cbb, ins);
4935                         args [4] = ins;
4936
4937                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
4938                                 int addr_reg;
4939
4940                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4941
4942                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4943                                 addr_reg = ins->dreg;
4944                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4945                         } else {
4946                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4947                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4948                         }
4949                 } else {
4950                         EMIT_NEW_ICONST (cfg, args [3], 0);
4951                         EMIT_NEW_ICONST (cfg, args [4], 0);
4952                 }
4953                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4954                 emit_widen = FALSE;
4955
4956                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
4957                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
4958                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4959                         MonoInst *add;
4960
4961                         /* Unbox */
4962                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4963                         MONO_ADD_INS (cfg->cbb, add);
4964                         /* Load value */
4965                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4966                         MONO_ADD_INS (cfg->cbb, ins);
4967                         /* ins represents the call result */
4968                 }
4969         } else {
4970                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4971         }
4972
4973         *ref_emit_widen = emit_widen;
4974         *ref_bblock = bblock;
4975
4976         return ins;
4977
4978  exception_exit:
4979         return NULL;
4980 }
4981
4982 static void
4983 mono_emit_load_got_addr (MonoCompile *cfg)
4984 {
4985         MonoInst *getaddr, *dummy_use;
4986
4987         if (!cfg->got_var || cfg->got_var_allocated)
4988                 return;
4989
4990         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4991         getaddr->cil_code = cfg->header->code;
4992         getaddr->dreg = cfg->got_var->dreg;
4993
4994         /* Add it to the start of the first bblock */
4995         if (cfg->bb_entry->code) {
4996                 getaddr->next = cfg->bb_entry->code;
4997                 cfg->bb_entry->code = getaddr;
4998         }
4999         else
5000                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5001
5002         cfg->got_var_allocated = TRUE;
5003
5004         /* 
5005          * Add a dummy use to keep the got_var alive, since real uses might
5006          * only be generated by the back ends.
5007          * Add it to end_bblock, so the variable's lifetime covers the whole
5008          * method.
5009          * It would be better to make the usage of the got var explicit in all
5010          * cases when the backend needs it (i.e. calls, throw etc.), so this
5011          * wouldn't be needed.
5012          */
5013         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5014         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5015 }
5016
5017 static int inline_limit;
5018 static gboolean inline_limit_inited;
5019
5020 static gboolean
5021 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5022 {
5023         MonoMethodHeaderSummary header;
5024         MonoVTable *vtable;
5025 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5026         MonoMethodSignature *sig = mono_method_signature (method);
5027         int i;
5028 #endif
5029
5030         if (cfg->disable_inline)
5031                 return FALSE;
5032         if (cfg->generic_sharing_context)
5033                 return FALSE;
5034
5035         if (cfg->inline_depth > 10)
5036                 return FALSE;
5037
5038 #ifdef MONO_ARCH_HAVE_LMF_OPS
5039         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5040                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5041             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5042                 return TRUE;
5043 #endif
5044
5045
5046         if (!mono_method_get_header_summary (method, &header))
5047                 return FALSE;
5048
5049         /*runtime, icall and pinvoke are checked by summary call*/
5050         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5051             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5052             (mono_class_is_marshalbyref (method->klass)) ||
5053             header.has_clauses)
5054                 return FALSE;
5055
5056         /* also consider num_locals? */
5057         /* Do the size check early to avoid creating vtables */
5058         if (!inline_limit_inited) {
5059                 if (g_getenv ("MONO_INLINELIMIT"))
5060                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5061                 else
5062                         inline_limit = INLINE_LENGTH_LIMIT;
5063                 inline_limit_inited = TRUE;
5064         }
5065         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5066                 return FALSE;
5067
5068         /*
5069          * if we can initialize the class of the method right away, we do,
5070          * otherwise we don't allow inlining if the class needs initialization,
5071          * since it would mean inserting a call to mono_runtime_class_init()
5072          * inside the inlined code
5073          */
5074         if (!(cfg->opt & MONO_OPT_SHARED)) {
5075                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5076                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5077                         vtable = mono_class_vtable (cfg->domain, method->klass);
5078                         if (!vtable)
5079                                 return FALSE;
5080                         if (!cfg->compile_aot)
5081                                 mono_runtime_class_init (vtable);
5082                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5083                         if (cfg->run_cctors && method->klass->has_cctor) {
5084                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5085                                 if (!method->klass->runtime_info)
5086                                         /* No vtable created yet */
5087                                         return FALSE;
5088                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5089                                 if (!vtable)
5090                                         return FALSE;
5091                                 /* This makes so that inline cannot trigger */
5092                                 /* .cctors: too many apps depend on them */
5093                                 /* running with a specific order... */
5094                                 if (! vtable->initialized)
5095                                         return FALSE;
5096                                 mono_runtime_class_init (vtable);
5097                         }
5098                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5099                         if (!method->klass->runtime_info)
5100                                 /* No vtable created yet */
5101                                 return FALSE;
5102                         vtable = mono_class_vtable (cfg->domain, method->klass);
5103                         if (!vtable)
5104                                 return FALSE;
5105                         if (!vtable->initialized)
5106                                 return FALSE;
5107                 }
5108         } else {
5109                 /* 
5110                  * If we're compiling for shared code
5111                  * the cctor will need to be run at aot method load time, for example,
5112                  * or at the end of the compilation of the inlining method.
5113                  */
5114                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5115                         return FALSE;
5116         }
5117
5118         /*
5119          * CAS - do not inline methods with declarative security
5120          * Note: this has to be before any possible return TRUE;
5121          */
5122         if (mono_security_method_has_declsec (method))
5123                 return FALSE;
5124
5125 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5126         if (mono_arch_is_soft_float ()) {
5127                 /* FIXME: */
5128                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5129                         return FALSE;
5130                 for (i = 0; i < sig->param_count; ++i)
5131                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5132                                 return FALSE;
5133         }
5134 #endif
5135
5136         if (g_list_find (cfg->dont_inline, method))
5137                 return FALSE;
5138
5139         return TRUE;
5140 }
5141
5142 static gboolean
5143 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5144 {
5145         if (!cfg->compile_aot) {
5146                 g_assert (vtable);
5147                 if (vtable->initialized)
5148                         return FALSE;
5149         }
5150
5151         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5152                 if (cfg->method == method)
5153                         return FALSE;
5154         }
5155
5156         if (!mono_class_needs_cctor_run (klass, method))
5157                 return FALSE;
5158
5159         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5160                 /* The initialization is already done before the method is called */
5161                 return FALSE;
5162
5163         return TRUE;
5164 }
5165
5166 static MonoInst*
5167 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5168 {
5169         MonoInst *ins;
5170         guint32 size;
5171         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5172         int context_used;
5173
5174         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5175                 size = -1;
5176         } else {
5177                 mono_class_init (klass);
5178                 size = mono_class_array_element_size (klass);
5179         }
5180
5181         mult_reg = alloc_preg (cfg);
5182         array_reg = arr->dreg;
5183         index_reg = index->dreg;
5184
5185 #if SIZEOF_REGISTER == 8
5186         /* The array reg is 64 bits but the index reg is only 32 */
5187         if (COMPILE_LLVM (cfg)) {
5188                 /* Not needed */
5189                 index2_reg = index_reg;
5190         } else {
5191                 index2_reg = alloc_preg (cfg);
5192                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5193         }
5194 #else
5195         if (index->type == STACK_I8) {
5196                 index2_reg = alloc_preg (cfg);
5197                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5198         } else {
5199                 index2_reg = index_reg;
5200         }
5201 #endif
5202
5203         if (bcheck)
5204                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5205
5206 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5207         if (size == 1 || size == 2 || size == 4 || size == 8) {
5208                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5209
5210                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5211                 ins->klass = mono_class_get_element_class (klass);
5212                 ins->type = STACK_MP;
5213
5214                 return ins;
5215         }
5216 #endif          
5217
5218         add_reg = alloc_ireg_mp (cfg);
5219
5220         if (size == -1) {
5221                 MonoInst *rgctx_ins;
5222
5223                 /* gsharedvt */
5224                 g_assert (cfg->generic_sharing_context);
5225                 context_used = mini_class_check_context_used (cfg, klass);
5226                 g_assert (context_used);
5227                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5228                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5229         } else {
5230                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5231         }
5232         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5233         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5234         ins->klass = mono_class_get_element_class (klass);
5235         ins->type = STACK_MP;
5236         MONO_ADD_INS (cfg->cbb, ins);
5237
5238         return ins;
5239 }
5240
5241 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5242 static MonoInst*
5243 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5244 {
5245         int bounds_reg = alloc_preg (cfg);
5246         int add_reg = alloc_ireg_mp (cfg);
5247         int mult_reg = alloc_preg (cfg);
5248         int mult2_reg = alloc_preg (cfg);
5249         int low1_reg = alloc_preg (cfg);
5250         int low2_reg = alloc_preg (cfg);
5251         int high1_reg = alloc_preg (cfg);
5252         int high2_reg = alloc_preg (cfg);
5253         int realidx1_reg = alloc_preg (cfg);
5254         int realidx2_reg = alloc_preg (cfg);
5255         int sum_reg = alloc_preg (cfg);
5256         int index1, index2, tmpreg;
5257         MonoInst *ins;
5258         guint32 size;
5259
5260         mono_class_init (klass);
5261         size = mono_class_array_element_size (klass);
5262
5263         index1 = index_ins1->dreg;
5264         index2 = index_ins2->dreg;
5265
5266 #if SIZEOF_REGISTER == 8
5267         /* The array reg is 64 bits but the index reg is only 32 */
5268         if (COMPILE_LLVM (cfg)) {
5269                 /* Not needed */
5270         } else {
5271                 tmpreg = alloc_preg (cfg);
5272                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5273                 index1 = tmpreg;
5274                 tmpreg = alloc_preg (cfg);
5275                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5276                 index2 = tmpreg;
5277         }
5278 #else
5279         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5280         tmpreg = -1;
5281 #endif
5282
5283         /* range checking */
5284         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5285                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5286
5287         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5288                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5289         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5290         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5291                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5292         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5293         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5294
5295         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5296                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5297         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5298         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5299                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5300         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5301         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5302
5303         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5304         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5305         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5306         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5307         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5308
5309         ins->type = STACK_MP;
5310         ins->klass = klass;
5311         MONO_ADD_INS (cfg->cbb, ins);
5312
5313         return ins;
5314 }
5315 #endif
5316
5317 static MonoInst*
5318 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5319 {
5320         int rank;
5321         MonoInst *addr;
5322         MonoMethod *addr_method;
5323         int element_size;
5324         MonoClass *eclass = cmethod->klass->element_class;
5325
5326         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5327
5328         if (rank == 1)
5329                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5330
5331 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5332         /* emit_ldelema_2 depends on OP_LMUL */
5333         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5334                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5335         }
5336 #endif
5337
5338         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5339                 element_size = 0;
5340         else
5341                 element_size = mono_class_array_element_size (eclass);
5342         addr_method = mono_marshal_get_array_address (rank, element_size);
5343         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5344
5345         return addr;
5346 }
5347
5348 static MonoBreakPolicy
5349 always_insert_breakpoint (MonoMethod *method)
5350 {
5351         return MONO_BREAK_POLICY_ALWAYS;
5352 }
5353
5354 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5355
5356 /**
5357  * mono_set_break_policy:
5358  * policy_callback: the new callback function
5359  *
5360  * Allow embedders to decide wherther to actually obey breakpoint instructions
5361  * (both break IL instructions and Debugger.Break () method calls), for example
5362  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5363  * untrusted or semi-trusted code.
5364  *
5365  * @policy_callback will be called every time a break point instruction needs to
5366  * be inserted with the method argument being the method that calls Debugger.Break()
5367  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5368  * if it wants the breakpoint to not be effective in the given method.
5369  * #MONO_BREAK_POLICY_ALWAYS is the default.
5370  */
5371 void
5372 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5373 {
5374         if (policy_callback)
5375                 break_policy_func = policy_callback;
5376         else
5377                 break_policy_func = always_insert_breakpoint;
5378 }
5379
5380 static gboolean
5381 should_insert_brekpoint (MonoMethod *method) {
5382         switch (break_policy_func (method)) {
5383         case MONO_BREAK_POLICY_ALWAYS:
5384                 return TRUE;
5385         case MONO_BREAK_POLICY_NEVER:
5386                 return FALSE;
5387         case MONO_BREAK_POLICY_ON_DBG:
5388                 g_warning ("mdb no longer supported");
5389                 return FALSE;
5390         default:
5391                 g_warning ("Incorrect value returned from break policy callback");
5392                 return FALSE;
5393         }
5394 }
5395
5396 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5397 static MonoInst*
5398 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5399 {
5400         MonoInst *addr, *store, *load;
5401         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5402
5403         /* the bounds check is already done by the callers */
5404         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5405         if (is_set) {
5406                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5407                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5408                 if (mini_type_is_reference (cfg, fsig->params [2]))
5409                         emit_write_barrier (cfg, addr, load);
5410         } else {
5411                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5412                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5413         }
5414         return store;
5415 }
5416
5417
5418 static gboolean
5419 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5420 {
5421         return mini_type_is_reference (cfg, &klass->byval_arg);
5422 }
5423
5424 static MonoInst*
5425 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5426 {
5427         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5428                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5429                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5430                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5431                 MonoInst *iargs [3];
5432
5433                 if (!helper->slot)
5434                         mono_class_setup_vtable (obj_array);
5435                 g_assert (helper->slot);
5436
5437                 if (sp [0]->type != STACK_OBJ)
5438                         return NULL;
5439                 if (sp [2]->type != STACK_OBJ)
5440                         return NULL;
5441
5442                 iargs [2] = sp [2];
5443                 iargs [1] = sp [1];
5444                 iargs [0] = sp [0];
5445
5446                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5447         } else {
5448                 MonoInst *ins;
5449
5450                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5451                         MonoInst *addr;
5452
5453                         // FIXME-VT: OP_ICONST optimization
5454                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5455                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5456                         ins->opcode = OP_STOREV_MEMBASE;
5457                 } else if (sp [1]->opcode == OP_ICONST) {
5458                         int array_reg = sp [0]->dreg;
5459                         int index_reg = sp [1]->dreg;
5460                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5461
5462                         if (safety_checks)
5463                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5464                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5465                 } else {
5466                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5467                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5468                         if (generic_class_is_reference_type (cfg, klass))
5469                                 emit_write_barrier (cfg, addr, sp [2]);
5470                 }
5471                 return ins;
5472         }
5473 }
5474
5475 static MonoInst*
5476 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5477 {
5478         MonoClass *eklass;
5479         
5480         if (is_set)
5481                 eklass = mono_class_from_mono_type (fsig->params [2]);
5482         else
5483                 eklass = mono_class_from_mono_type (fsig->ret);
5484
5485         if (is_set) {
5486                 return emit_array_store (cfg, eklass, args, FALSE);
5487         } else {
5488                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5489                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5490                 return ins;
5491         }
5492 }
5493
5494 static gboolean
5495 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5496 {
5497         uint32_t align;
5498
5499         //Only allow for valuetypes
5500         if (!param_klass->valuetype || !return_klass->valuetype)
5501                 return FALSE;
5502
5503         //That are blitable
5504         if (param_klass->has_references || return_klass->has_references)
5505                 return FALSE;
5506
5507         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5508         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5509                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5510                 return FALSE;
5511
5512         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5513                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5514                 return FALSE;
5515
5516         //And have the same size
5517         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5518                 return FALSE;
5519         return TRUE;
5520 }
5521
5522 static MonoInst*
5523 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5524 {
5525         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5526         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5527
5528         //Valuetypes that are semantically equivalent
5529         if (is_unsafe_mov_compatible (param_klass, return_klass))
5530                 return args [0];
5531
5532         //Arrays of valuetypes that are semantically equivalent
5533         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5534                 return args [0];
5535
5536         return NULL;
5537 }
5538
5539 static MonoInst*
5540 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5541 {
5542 #ifdef MONO_ARCH_SIMD_INTRINSICS
5543         MonoInst *ins = NULL;
5544
5545         if (cfg->opt & MONO_OPT_SIMD) {
5546                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5547                 if (ins)
5548                         return ins;
5549         }
5550 #endif
5551
5552         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5553 }
5554
5555 static MonoInst*
5556 emit_memory_barrier (MonoCompile *cfg, int kind)
5557 {
5558         MonoInst *ins = NULL;
5559         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5560         MONO_ADD_INS (cfg->cbb, ins);
5561         ins->backend.memory_barrier_kind = kind;
5562
5563         return ins;
5564 }
5565
5566 static MonoInst*
5567 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5568 {
5569         MonoInst *ins = NULL;
5570         int opcode = 0;
5571
5572         /* The LLVM backend supports these intrinsics */
5573         if (cmethod->klass == mono_defaults.math_class) {
5574                 if (strcmp (cmethod->name, "Sin") == 0) {
5575                         opcode = OP_SIN;
5576                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5577                         opcode = OP_COS;
5578                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5579                         opcode = OP_SQRT;
5580                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5581                         opcode = OP_ABS;
5582                 }
5583
5584                 if (opcode && fsig->param_count == 1) {
5585                         MONO_INST_NEW (cfg, ins, opcode);
5586                         ins->type = STACK_R8;
5587                         ins->dreg = mono_alloc_freg (cfg);
5588                         ins->sreg1 = args [0]->dreg;
5589                         MONO_ADD_INS (cfg->cbb, ins);
5590                 }
5591
5592                 opcode = 0;
5593                 if (cfg->opt & MONO_OPT_CMOV) {
5594                         if (strcmp (cmethod->name, "Min") == 0) {
5595                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5596                                         opcode = OP_IMIN;
5597                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5598                                         opcode = OP_IMIN_UN;
5599                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5600                                         opcode = OP_LMIN;
5601                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5602                                         opcode = OP_LMIN_UN;
5603                         } else if (strcmp (cmethod->name, "Max") == 0) {
5604                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5605                                         opcode = OP_IMAX;
5606                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5607                                         opcode = OP_IMAX_UN;
5608                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5609                                         opcode = OP_LMAX;
5610                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5611                                         opcode = OP_LMAX_UN;
5612                         }
5613                 }
5614
5615                 if (opcode && fsig->param_count == 2) {
5616                         MONO_INST_NEW (cfg, ins, opcode);
5617                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5618                         ins->dreg = mono_alloc_ireg (cfg);
5619                         ins->sreg1 = args [0]->dreg;
5620                         ins->sreg2 = args [1]->dreg;
5621                         MONO_ADD_INS (cfg->cbb, ins);
5622                 }
5623         }
5624
5625         return ins;
5626 }
5627
5628 static MonoInst*
5629 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5630 {
5631         if (cmethod->klass == mono_defaults.array_class) {
5632                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5633                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5634                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5635                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5636                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5637                         return emit_array_unsafe_mov (cfg, fsig, args);
5638         }
5639
5640         return NULL;
5641 }
5642
5643 static MonoInst*
5644 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5645 {
5646         MonoInst *ins = NULL;
5647         
5648         static MonoClass *runtime_helpers_class = NULL;
5649         if (! runtime_helpers_class)
5650                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5651                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5652
5653         if (cmethod->klass == mono_defaults.string_class) {
5654                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5655                         int dreg = alloc_ireg (cfg);
5656                         int index_reg = alloc_preg (cfg);
5657                         int add_reg = alloc_preg (cfg);
5658
5659 #if SIZEOF_REGISTER == 8
5660                         /* The array reg is 64 bits but the index reg is only 32 */
5661                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5662 #else
5663                         index_reg = args [1]->dreg;
5664 #endif  
5665                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5666
5667 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5668                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5669                         add_reg = ins->dreg;
5670                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5671                                                                    add_reg, 0);
5672 #else
5673                         int mult_reg = alloc_preg (cfg);
5674                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5675                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5676                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5677                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5678 #endif
5679                         type_from_op (cfg, ins, NULL, NULL);
5680                         return ins;
5681                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5682                         int dreg = alloc_ireg (cfg);
5683                         /* Decompose later to allow more optimizations */
5684                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5685                         ins->type = STACK_I4;
5686                         ins->flags |= MONO_INST_FAULT;
5687                         cfg->cbb->has_array_access = TRUE;
5688                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5689
5690                         return ins;
5691                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5692                         int mult_reg = alloc_preg (cfg);
5693                         int add_reg = alloc_preg (cfg);
5694
5695                         /* The corlib functions check for oob already. */
5696                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5697                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5698                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5699                         return cfg->cbb->last_ins;
5700                 } else 
5701                         return NULL;
5702         } else if (cmethod->klass == mono_defaults.object_class) {
5703
5704                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5705                         int dreg = alloc_ireg_ref (cfg);
5706                         int vt_reg = alloc_preg (cfg);
5707                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5708                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5709                         type_from_op (cfg, ins, NULL, NULL);
5710
5711                         return ins;
5712 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5713                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5714                         int dreg = alloc_ireg (cfg);
5715                         int t1 = alloc_ireg (cfg);
5716         
5717                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5718                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5719                         ins->type = STACK_I4;
5720
5721                         return ins;
5722 #endif
5723                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5724                         MONO_INST_NEW (cfg, ins, OP_NOP);
5725                         MONO_ADD_INS (cfg->cbb, ins);
5726                         return ins;
5727                 } else
5728                         return NULL;
5729         } else if (cmethod->klass == mono_defaults.array_class) {
5730                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5731                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5732                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5733                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5734
5735 #ifndef MONO_BIG_ARRAYS
5736                 /*
5737                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5738                  * Array methods.
5739                  */
5740                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5741                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5742                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5743                         int dreg = alloc_ireg (cfg);
5744                         int bounds_reg = alloc_ireg_mp (cfg);
5745                         MonoBasicBlock *end_bb, *szarray_bb;
5746                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5747
5748                         NEW_BBLOCK (cfg, end_bb);
5749                         NEW_BBLOCK (cfg, szarray_bb);
5750
5751                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5752                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5753                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5754                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5755                         /* Non-szarray case */
5756                         if (get_length)
5757                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5758                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5759                         else
5760                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5761                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5762                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5763                         MONO_START_BB (cfg, szarray_bb);
5764                         /* Szarray case */
5765                         if (get_length)
5766                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5767                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5768                         else
5769                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5770                         MONO_START_BB (cfg, end_bb);
5771
5772                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5773                         ins->type = STACK_I4;
5774                         
5775                         return ins;
5776                 }
5777 #endif
5778
5779                 if (cmethod->name [0] != 'g')
5780                         return NULL;
5781
5782                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5783                         int dreg = alloc_ireg (cfg);
5784                         int vtable_reg = alloc_preg (cfg);
5785                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5786                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5787                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5788                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5789                         type_from_op (cfg, ins, NULL, NULL);
5790
5791                         return ins;
5792                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5793                         int dreg = alloc_ireg (cfg);
5794
5795                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5796                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5797                         type_from_op (cfg, ins, NULL, NULL);
5798
5799                         return ins;
5800                 } else
5801                         return NULL;
5802         } else if (cmethod->klass == runtime_helpers_class) {
5803
5804                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5805                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5806                         return ins;
5807                 } else
5808                         return NULL;
5809         } else if (cmethod->klass == mono_defaults.thread_class) {
5810                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5811                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5812                         MONO_ADD_INS (cfg->cbb, ins);
5813                         return ins;
5814                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5815                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5816                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5817                         guint32 opcode = 0;
5818                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5819
5820                         if (fsig->params [0]->type == MONO_TYPE_I1)
5821                                 opcode = OP_LOADI1_MEMBASE;
5822                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5823                                 opcode = OP_LOADU1_MEMBASE;
5824                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5825                                 opcode = OP_LOADI2_MEMBASE;
5826                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5827                                 opcode = OP_LOADU2_MEMBASE;
5828                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5829                                 opcode = OP_LOADI4_MEMBASE;
5830                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5831                                 opcode = OP_LOADU4_MEMBASE;
5832                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5833                                 opcode = OP_LOADI8_MEMBASE;
5834                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5835                                 opcode = OP_LOADR4_MEMBASE;
5836                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5837                                 opcode = OP_LOADR8_MEMBASE;
5838                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5839                                 opcode = OP_LOAD_MEMBASE;
5840
5841                         if (opcode) {
5842                                 MONO_INST_NEW (cfg, ins, opcode);
5843                                 ins->inst_basereg = args [0]->dreg;
5844                                 ins->inst_offset = 0;
5845                                 MONO_ADD_INS (cfg->cbb, ins);
5846
5847                                 switch (fsig->params [0]->type) {
5848                                 case MONO_TYPE_I1:
5849                                 case MONO_TYPE_U1:
5850                                 case MONO_TYPE_I2:
5851                                 case MONO_TYPE_U2:
5852                                 case MONO_TYPE_I4:
5853                                 case MONO_TYPE_U4:
5854                                         ins->dreg = mono_alloc_ireg (cfg);
5855                                         ins->type = STACK_I4;
5856                                         break;
5857                                 case MONO_TYPE_I8:
5858                                 case MONO_TYPE_U8:
5859                                         ins->dreg = mono_alloc_lreg (cfg);
5860                                         ins->type = STACK_I8;
5861                                         break;
5862                                 case MONO_TYPE_I:
5863                                 case MONO_TYPE_U:
5864                                         ins->dreg = mono_alloc_ireg (cfg);
5865 #if SIZEOF_REGISTER == 8
5866                                         ins->type = STACK_I8;
5867 #else
5868                                         ins->type = STACK_I4;
5869 #endif
5870                                         break;
5871                                 case MONO_TYPE_R4:
5872                                 case MONO_TYPE_R8:
5873                                         ins->dreg = mono_alloc_freg (cfg);
5874                                         ins->type = STACK_R8;
5875                                         break;
5876                                 default:
5877                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5878                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5879                                         ins->type = STACK_OBJ;
5880                                         break;
5881                                 }
5882
5883                                 if (opcode == OP_LOADI8_MEMBASE)
5884                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5885
5886                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5887
5888                                 return ins;
5889                         }
5890                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5891                         guint32 opcode = 0;
5892                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5893
5894                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5895                                 opcode = OP_STOREI1_MEMBASE_REG;
5896                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5897                                 opcode = OP_STOREI2_MEMBASE_REG;
5898                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5899                                 opcode = OP_STOREI4_MEMBASE_REG;
5900                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5901                                 opcode = OP_STOREI8_MEMBASE_REG;
5902                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5903                                 opcode = OP_STORER4_MEMBASE_REG;
5904                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5905                                 opcode = OP_STORER8_MEMBASE_REG;
5906                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5907                                 opcode = OP_STORE_MEMBASE_REG;
5908
5909                         if (opcode) {
5910                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5911
5912                                 MONO_INST_NEW (cfg, ins, opcode);
5913                                 ins->sreg1 = args [1]->dreg;
5914                                 ins->inst_destbasereg = args [0]->dreg;
5915                                 ins->inst_offset = 0;
5916                                 MONO_ADD_INS (cfg->cbb, ins);
5917
5918                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5919                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5920
5921                                 return ins;
5922                         }
5923                 }
5924         } else if (cmethod->klass == mono_defaults.monitor_class) {
5925 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5926                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5927                         MonoCallInst *call;
5928
5929                         if (COMPILE_LLVM (cfg)) {
5930                                 /* 
5931                                  * Pass the argument normally, the LLVM backend will handle the
5932                                  * calling convention problems.
5933                                  */
5934                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5935                         } else {
5936                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5937                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5938                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5939                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5940                         }
5941
5942                         return (MonoInst*)call;
5943 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5944                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5945                         MonoCallInst *call;
5946
5947                         if (COMPILE_LLVM (cfg)) {
5948                                 /*
5949                                  * Pass the argument normally, the LLVM backend will handle the
5950                                  * calling convention problems.
5951                                  */
5952                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5953                         } else {
5954                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5955                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5956                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5957                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5958                         }
5959
5960                         return (MonoInst*)call;
5961 #endif
5962                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
5963                         MonoCallInst *call;
5964
5965                         if (COMPILE_LLVM (cfg)) {
5966                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5967                         } else {
5968                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5969                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5970                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5971                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5972                         }
5973
5974                         return (MonoInst*)call;
5975                 }
5976 #endif
5977         } else if (cmethod->klass->image == mono_defaults.corlib &&
5978                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5979                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5980                 ins = NULL;
5981
5982 #if SIZEOF_REGISTER == 8
5983                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5984                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5985                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5986                                 ins->dreg = mono_alloc_preg (cfg);
5987                                 ins->sreg1 = args [0]->dreg;
5988                                 ins->type = STACK_I8;
5989                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5990                                 MONO_ADD_INS (cfg->cbb, ins);
5991                         } else {
5992                                 MonoInst *load_ins;
5993
5994                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5995
5996                                 /* 64 bit reads are already atomic */
5997                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5998                                 load_ins->dreg = mono_alloc_preg (cfg);
5999                                 load_ins->inst_basereg = args [0]->dreg;
6000                                 load_ins->inst_offset = 0;
6001                                 load_ins->type = STACK_I8;
6002                                 MONO_ADD_INS (cfg->cbb, load_ins);
6003
6004                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6005
6006                                 ins = load_ins;
6007                         }
6008                 }
6009 #endif
6010
6011                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6012                         MonoInst *ins_iconst;
6013                         guint32 opcode = 0;
6014
6015                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6016                                 opcode = OP_ATOMIC_ADD_I4;
6017                                 cfg->has_atomic_add_i4 = TRUE;
6018                         }
6019 #if SIZEOF_REGISTER == 8
6020                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6021                                 opcode = OP_ATOMIC_ADD_I8;
6022 #endif
6023                         if (opcode) {
6024                                 if (!mono_arch_opcode_supported (opcode))
6025                                         return NULL;
6026                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6027                                 ins_iconst->inst_c0 = 1;
6028                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6029                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6030
6031                                 MONO_INST_NEW (cfg, ins, opcode);
6032                                 ins->dreg = mono_alloc_ireg (cfg);
6033                                 ins->inst_basereg = args [0]->dreg;
6034                                 ins->inst_offset = 0;
6035                                 ins->sreg2 = ins_iconst->dreg;
6036                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6037                                 MONO_ADD_INS (cfg->cbb, ins);
6038                         }
6039                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6040                         MonoInst *ins_iconst;
6041                         guint32 opcode = 0;
6042
6043                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6044                                 opcode = OP_ATOMIC_ADD_I4;
6045                                 cfg->has_atomic_add_i4 = TRUE;
6046                         }
6047 #if SIZEOF_REGISTER == 8
6048                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6049                                 opcode = OP_ATOMIC_ADD_I8;
6050 #endif
6051                         if (opcode) {
6052                                 if (!mono_arch_opcode_supported (opcode))
6053                                         return NULL;
6054                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6055                                 ins_iconst->inst_c0 = -1;
6056                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6057                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6058
6059                                 MONO_INST_NEW (cfg, ins, opcode);
6060                                 ins->dreg = mono_alloc_ireg (cfg);
6061                                 ins->inst_basereg = args [0]->dreg;
6062                                 ins->inst_offset = 0;
6063                                 ins->sreg2 = ins_iconst->dreg;
6064                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6065                                 MONO_ADD_INS (cfg->cbb, ins);
6066                         }
6067                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6068                         guint32 opcode = 0;
6069
6070                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6071                                 opcode = OP_ATOMIC_ADD_I4;
6072                                 cfg->has_atomic_add_i4 = TRUE;
6073                         }
6074 #if SIZEOF_REGISTER == 8
6075                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6076                                 opcode = OP_ATOMIC_ADD_I8;
6077 #endif
6078                         if (opcode) {
6079                                 if (!mono_arch_opcode_supported (opcode))
6080                                         return NULL;
6081                                 MONO_INST_NEW (cfg, ins, opcode);
6082                                 ins->dreg = mono_alloc_ireg (cfg);
6083                                 ins->inst_basereg = args [0]->dreg;
6084                                 ins->inst_offset = 0;
6085                                 ins->sreg2 = args [1]->dreg;
6086                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6087                                 MONO_ADD_INS (cfg->cbb, ins);
6088                         }
6089                 }
6090                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6091                         MonoInst *f2i = NULL, *i2f;
6092                         guint32 opcode, f2i_opcode, i2f_opcode;
6093                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6094                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6095
6096                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6097                             fsig->params [0]->type == MONO_TYPE_R4) {
6098                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6099                                 f2i_opcode = OP_MOVE_F_TO_I4;
6100                                 i2f_opcode = OP_MOVE_I4_TO_F;
6101                                 cfg->has_atomic_exchange_i4 = TRUE;
6102                         }
6103 #if SIZEOF_REGISTER == 8
6104                         else if (is_ref ||
6105                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6106                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6107                                  fsig->params [0]->type == MONO_TYPE_I) {
6108                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6109                                 f2i_opcode = OP_MOVE_F_TO_I8;
6110                                 i2f_opcode = OP_MOVE_I8_TO_F;
6111                         }
6112 #else
6113                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6114                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6115                                 cfg->has_atomic_exchange_i4 = TRUE;
6116                         }
6117 #endif
6118                         else
6119                                 return NULL;
6120
6121                         if (!mono_arch_opcode_supported (opcode))
6122                                 return NULL;
6123
6124                         if (is_float) {
6125                                 /* TODO: Decompose these opcodes instead of bailing here. */
6126                                 if (COMPILE_SOFT_FLOAT (cfg))
6127                                         return NULL;
6128
6129                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6130                                 f2i->dreg = mono_alloc_ireg (cfg);
6131                                 f2i->sreg1 = args [1]->dreg;
6132                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6133                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6134                                 MONO_ADD_INS (cfg->cbb, f2i);
6135                         }
6136
6137                         MONO_INST_NEW (cfg, ins, opcode);
6138                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6139                         ins->inst_basereg = args [0]->dreg;
6140                         ins->inst_offset = 0;
6141                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6142                         MONO_ADD_INS (cfg->cbb, ins);
6143
6144                         switch (fsig->params [0]->type) {
6145                         case MONO_TYPE_I4:
6146                                 ins->type = STACK_I4;
6147                                 break;
6148                         case MONO_TYPE_I8:
6149                                 ins->type = STACK_I8;
6150                                 break;
6151                         case MONO_TYPE_I:
6152 #if SIZEOF_REGISTER == 8
6153                                 ins->type = STACK_I8;
6154 #else
6155                                 ins->type = STACK_I4;
6156 #endif
6157                                 break;
6158                         case MONO_TYPE_R4:
6159                         case MONO_TYPE_R8:
6160                                 ins->type = STACK_R8;
6161                                 break;
6162                         default:
6163                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6164                                 ins->type = STACK_OBJ;
6165                                 break;
6166                         }
6167
6168                         if (is_float) {
6169                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6170                                 i2f->dreg = mono_alloc_freg (cfg);
6171                                 i2f->sreg1 = ins->dreg;
6172                                 i2f->type = STACK_R8;
6173                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6174                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6175                                 MONO_ADD_INS (cfg->cbb, i2f);
6176
6177                                 ins = i2f;
6178                         }
6179
6180                         if (cfg->gen_write_barriers && is_ref)
6181                                 emit_write_barrier (cfg, args [0], args [1]);
6182                 }
6183                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6184                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6185                         guint32 opcode, f2i_opcode, i2f_opcode;
6186                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6187                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6188
6189                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6190                             fsig->params [1]->type == MONO_TYPE_R4) {
6191                                 opcode = OP_ATOMIC_CAS_I4;
6192                                 f2i_opcode = OP_MOVE_F_TO_I4;
6193                                 i2f_opcode = OP_MOVE_I4_TO_F;
6194                                 cfg->has_atomic_cas_i4 = TRUE;
6195                         }
6196 #if SIZEOF_REGISTER == 8
6197                         else if (is_ref ||
6198                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6199                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6200                                  fsig->params [1]->type == MONO_TYPE_I) {
6201                                 opcode = OP_ATOMIC_CAS_I8;
6202                                 f2i_opcode = OP_MOVE_F_TO_I8;
6203                                 i2f_opcode = OP_MOVE_I8_TO_F;
6204                         }
6205 #else
6206                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6207                                 opcode = OP_ATOMIC_CAS_I4;
6208                                 cfg->has_atomic_cas_i4 = TRUE;
6209                         }
6210 #endif
6211                         else
6212                                 return NULL;
6213
6214                         if (!mono_arch_opcode_supported (opcode))
6215                                 return NULL;
6216
6217                         if (is_float) {
6218                                 /* TODO: Decompose these opcodes instead of bailing here. */
6219                                 if (COMPILE_SOFT_FLOAT (cfg))
6220                                         return NULL;
6221
6222                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6223                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6224                                 f2i_new->sreg1 = args [1]->dreg;
6225                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6226                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6227                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6228
6229                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6230                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6231                                 f2i_cmp->sreg1 = args [2]->dreg;
6232                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6233                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6234                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6235                         }
6236
6237                         MONO_INST_NEW (cfg, ins, opcode);
6238                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6239                         ins->sreg1 = args [0]->dreg;
6240                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6241                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6242                         MONO_ADD_INS (cfg->cbb, ins);
6243
6244                         switch (fsig->params [1]->type) {
6245                         case MONO_TYPE_I4:
6246                                 ins->type = STACK_I4;
6247                                 break;
6248                         case MONO_TYPE_I8:
6249                                 ins->type = STACK_I8;
6250                                 break;
6251                         case MONO_TYPE_I:
6252 #if SIZEOF_REGISTER == 8
6253                                 ins->type = STACK_I8;
6254 #else
6255                                 ins->type = STACK_I4;
6256 #endif
6257                                 break;
6258                         case MONO_TYPE_R4:
6259                         case MONO_TYPE_R8:
6260                                 ins->type = STACK_R8;
6261                                 break;
6262                         default:
6263                                 g_assert (mini_type_is_reference (cfg, fsig->params [1]));
6264                                 ins->type = STACK_OBJ;
6265                                 break;
6266                         }
6267
6268                         if (is_float) {
6269                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6270                                 i2f->dreg = mono_alloc_freg (cfg);
6271                                 i2f->sreg1 = ins->dreg;
6272                                 i2f->type = STACK_R8;
6273                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6274                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6275                                 MONO_ADD_INS (cfg->cbb, i2f);
6276
6277                                 ins = i2f;
6278                         }
6279
6280                         if (cfg->gen_write_barriers && is_ref)
6281                                 emit_write_barrier (cfg, args [0], args [1]);
6282                 }
6283                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6284                          fsig->params [1]->type == MONO_TYPE_I4) {
6285                         MonoInst *cmp, *ceq;
6286
6287                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6288                                 return NULL;
6289
6290                         /* int32 r = CAS (location, value, comparand); */
6291                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6292                         ins->dreg = alloc_ireg (cfg);
6293                         ins->sreg1 = args [0]->dreg;
6294                         ins->sreg2 = args [1]->dreg;
6295                         ins->sreg3 = args [2]->dreg;
6296                         ins->type = STACK_I4;
6297                         MONO_ADD_INS (cfg->cbb, ins);
6298
6299                         /* bool result = r == comparand; */
6300                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6301                         cmp->sreg1 = ins->dreg;
6302                         cmp->sreg2 = args [2]->dreg;
6303                         cmp->type = STACK_I4;
6304                         MONO_ADD_INS (cfg->cbb, cmp);
6305
6306                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6307                         ceq->dreg = alloc_ireg (cfg);
6308                         ceq->type = STACK_I4;
6309                         MONO_ADD_INS (cfg->cbb, ceq);
6310
6311                         /* *success = result; */
6312                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6313
6314                         cfg->has_atomic_cas_i4 = TRUE;
6315                 }
6316                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6317                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6318
6319                 if (ins)
6320                         return ins;
6321         } else if (cmethod->klass->image == mono_defaults.corlib &&
6322                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6323                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6324                 ins = NULL;
6325
6326                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6327                         guint32 opcode = 0;
6328                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6329                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6330
6331                         if (fsig->params [0]->type == MONO_TYPE_I1)
6332                                 opcode = OP_ATOMIC_LOAD_I1;
6333                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6334                                 opcode = OP_ATOMIC_LOAD_U1;
6335                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6336                                 opcode = OP_ATOMIC_LOAD_I2;
6337                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6338                                 opcode = OP_ATOMIC_LOAD_U2;
6339                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6340                                 opcode = OP_ATOMIC_LOAD_I4;
6341                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6342                                 opcode = OP_ATOMIC_LOAD_U4;
6343                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6344                                 opcode = OP_ATOMIC_LOAD_R4;
6345                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6346                                 opcode = OP_ATOMIC_LOAD_R8;
6347 #if SIZEOF_REGISTER == 8
6348                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6349                                 opcode = OP_ATOMIC_LOAD_I8;
6350                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6351                                 opcode = OP_ATOMIC_LOAD_U8;
6352 #else
6353                         else if (fsig->params [0]->type == MONO_TYPE_I)
6354                                 opcode = OP_ATOMIC_LOAD_I4;
6355                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6356                                 opcode = OP_ATOMIC_LOAD_U4;
6357 #endif
6358
6359                         if (opcode) {
6360                                 if (!mono_arch_opcode_supported (opcode))
6361                                         return NULL;
6362
6363                                 MONO_INST_NEW (cfg, ins, opcode);
6364                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6365                                 ins->sreg1 = args [0]->dreg;
6366                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6367                                 MONO_ADD_INS (cfg->cbb, ins);
6368
6369                                 switch (fsig->params [0]->type) {
6370                                 case MONO_TYPE_BOOLEAN:
6371                                 case MONO_TYPE_I1:
6372                                 case MONO_TYPE_U1:
6373                                 case MONO_TYPE_I2:
6374                                 case MONO_TYPE_U2:
6375                                 case MONO_TYPE_I4:
6376                                 case MONO_TYPE_U4:
6377                                         ins->type = STACK_I4;
6378                                         break;
6379                                 case MONO_TYPE_I8:
6380                                 case MONO_TYPE_U8:
6381                                         ins->type = STACK_I8;
6382                                         break;
6383                                 case MONO_TYPE_I:
6384                                 case MONO_TYPE_U:
6385 #if SIZEOF_REGISTER == 8
6386                                         ins->type = STACK_I8;
6387 #else
6388                                         ins->type = STACK_I4;
6389 #endif
6390                                         break;
6391                                 case MONO_TYPE_R4:
6392                                 case MONO_TYPE_R8:
6393                                         ins->type = STACK_R8;
6394                                         break;
6395                                 default:
6396                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6397                                         ins->type = STACK_OBJ;
6398                                         break;
6399                                 }
6400                         }
6401                 }
6402
6403                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6404                         guint32 opcode = 0;
6405                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6406
6407                         if (fsig->params [0]->type == MONO_TYPE_I1)
6408                                 opcode = OP_ATOMIC_STORE_I1;
6409                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6410                                 opcode = OP_ATOMIC_STORE_U1;
6411                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6412                                 opcode = OP_ATOMIC_STORE_I2;
6413                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6414                                 opcode = OP_ATOMIC_STORE_U2;
6415                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6416                                 opcode = OP_ATOMIC_STORE_I4;
6417                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6418                                 opcode = OP_ATOMIC_STORE_U4;
6419                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6420                                 opcode = OP_ATOMIC_STORE_R4;
6421                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6422                                 opcode = OP_ATOMIC_STORE_R8;
6423 #if SIZEOF_REGISTER == 8
6424                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6425                                 opcode = OP_ATOMIC_STORE_I8;
6426                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6427                                 opcode = OP_ATOMIC_STORE_U8;
6428 #else
6429                         else if (fsig->params [0]->type == MONO_TYPE_I)
6430                                 opcode = OP_ATOMIC_STORE_I4;
6431                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6432                                 opcode = OP_ATOMIC_STORE_U4;
6433 #endif
6434
6435                         if (opcode) {
6436                                 if (!mono_arch_opcode_supported (opcode))
6437                                         return NULL;
6438
6439                                 MONO_INST_NEW (cfg, ins, opcode);
6440                                 ins->dreg = args [0]->dreg;
6441                                 ins->sreg1 = args [1]->dreg;
6442                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6443                                 MONO_ADD_INS (cfg->cbb, ins);
6444
6445                                 if (cfg->gen_write_barriers && is_ref)
6446                                         emit_write_barrier (cfg, args [0], args [1]);
6447                         }
6448                 }
6449
6450                 if (ins)
6451                         return ins;
6452         } else if (cmethod->klass->image == mono_defaults.corlib &&
6453                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6454                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6455                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6456                         if (should_insert_brekpoint (cfg->method)) {
6457                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6458                         } else {
6459                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6460                                 MONO_ADD_INS (cfg->cbb, ins);
6461                         }
6462                         return ins;
6463                 }
6464         } else if (cmethod->klass->image == mono_defaults.corlib &&
6465                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6466                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6467                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6468 #ifdef TARGET_WIN32
6469                         EMIT_NEW_ICONST (cfg, ins, 1);
6470 #else
6471                         EMIT_NEW_ICONST (cfg, ins, 0);
6472 #endif
6473                 }
6474         } else if (cmethod->klass == mono_defaults.math_class) {
6475                 /* 
6476                  * There is general branchless code for Min/Max, but it does not work for 
6477                  * all inputs:
6478                  * http://everything2.com/?node_id=1051618
6479                  */
6480         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6481                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6482                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6483                    !strcmp (cmethod->klass->name, "Selector")) {
6484 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6485                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6486                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6487                     cfg->compile_aot) {
6488                         MonoInst *pi;
6489                         MonoJumpInfoToken *ji;
6490                         MonoString *s;
6491
6492                         cfg->disable_llvm = TRUE;
6493
6494                         if (args [0]->opcode == OP_GOT_ENTRY) {
6495                                 pi = args [0]->inst_p1;
6496                                 g_assert (pi->opcode == OP_PATCH_INFO);
6497                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6498                                 ji = pi->inst_p0;
6499                         } else {
6500                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6501                                 ji = args [0]->inst_p0;
6502                         }
6503
6504                         NULLIFY_INS (args [0]);
6505
6506                         // FIXME: Ugly
6507                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6508                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6509                         ins->dreg = mono_alloc_ireg (cfg);
6510                         // FIXME: Leaks
6511                         ins->inst_p0 = mono_string_to_utf8 (s);
6512                         MONO_ADD_INS (cfg->cbb, ins);
6513                         return ins;
6514                 }
6515 #endif
6516         }
6517
6518 #ifdef MONO_ARCH_SIMD_INTRINSICS
6519         if (cfg->opt & MONO_OPT_SIMD) {
6520                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6521                 if (ins)
6522                         return ins;
6523         }
6524 #endif
6525
6526         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6527         if (ins)
6528                 return ins;
6529
6530         if (COMPILE_LLVM (cfg)) {
6531                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6532                 if (ins)
6533                         return ins;
6534         }
6535
6536         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6537 }
6538
6539 /*
6540  * This entry point could be used later for arbitrary method
6541  * redirection.
6542  */
6543 inline static MonoInst*
6544 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6545                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6546 {
6547         if (method->klass == mono_defaults.string_class) {
6548                 /* managed string allocation support */
6549                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6550                         MonoInst *iargs [2];
6551                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6552                         MonoMethod *managed_alloc = NULL;
6553
6554                         g_assert (vtable); /*Should not fail since it System.String*/
6555 #ifndef MONO_CROSS_COMPILE
6556                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6557 #endif
6558                         if (!managed_alloc)
6559                                 return NULL;
6560                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6561                         iargs [1] = args [0];
6562                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6563                 }
6564         }
6565         return NULL;
6566 }
6567
6568 static void
6569 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6570 {
6571         MonoInst *store, *temp;
6572         int i;
6573
6574         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6575                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6576
6577                 /*
6578                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6579                  * would be different than the MonoInst's used to represent arguments, and
6580                  * the ldelema implementation can't deal with that.
6581                  * Solution: When ldelema is used on an inline argument, create a var for 
6582                  * it, emit ldelema on that var, and emit the saving code below in
6583                  * inline_method () if needed.
6584                  */
6585                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6586                 cfg->args [i] = temp;
6587                 /* This uses cfg->args [i] which is set by the preceeding line */
6588                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6589                 store->cil_code = sp [0]->cil_code;
6590                 sp++;
6591         }
6592 }
6593
6594 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6595 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6596
6597 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6598 static gboolean
6599 check_inline_called_method_name_limit (MonoMethod *called_method)
6600 {
6601         int strncmp_result;
6602         static const char *limit = NULL;
6603         
6604         if (limit == NULL) {
6605                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6606
6607                 if (limit_string != NULL)
6608                         limit = limit_string;
6609                 else
6610                         limit = "";
6611         }
6612
6613         if (limit [0] != '\0') {
6614                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6615
6616                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6617                 g_free (called_method_name);
6618         
6619                 //return (strncmp_result <= 0);
6620                 return (strncmp_result == 0);
6621         } else {
6622                 return TRUE;
6623         }
6624 }
6625 #endif
6626
6627 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6628 static gboolean
6629 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6630 {
6631         int strncmp_result;
6632         static const char *limit = NULL;
6633         
6634         if (limit == NULL) {
6635                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6636                 if (limit_string != NULL) {
6637                         limit = limit_string;
6638                 } else {
6639                         limit = "";
6640                 }
6641         }
6642
6643         if (limit [0] != '\0') {
6644                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6645
6646                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6647                 g_free (caller_method_name);
6648         
6649                 //return (strncmp_result <= 0);
6650                 return (strncmp_result == 0);
6651         } else {
6652                 return TRUE;
6653         }
6654 }
6655 #endif
6656
6657 static void
6658 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6659 {
6660         static double r8_0 = 0.0;
6661         static float r4_0 = 0.0;
6662         MonoInst *ins;
6663         int t;
6664
6665         rtype = mini_get_underlying_type (cfg, rtype);
6666         t = rtype->type;
6667
6668         if (rtype->byref) {
6669                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6670         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6671                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6672         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6673                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6674         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6675                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6676                 ins->type = STACK_R4;
6677                 ins->inst_p0 = (void*)&r4_0;
6678                 ins->dreg = dreg;
6679                 MONO_ADD_INS (cfg->cbb, ins);
6680         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6681                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6682                 ins->type = STACK_R8;
6683                 ins->inst_p0 = (void*)&r8_0;
6684                 ins->dreg = dreg;
6685                 MONO_ADD_INS (cfg->cbb, ins);
6686         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6687                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6688                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6689         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6690                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6691         } else {
6692                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6693         }
6694 }
6695
6696 static void
6697 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6698 {
6699         int t;
6700
6701         rtype = mini_get_underlying_type (cfg, rtype);
6702         t = rtype->type;
6703
6704         if (rtype->byref) {
6705                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6706         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6707                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6708         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6709                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6710         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6711                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6712         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6713                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6714         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6715                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6716                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6717         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6718                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6719         } else {
6720                 emit_init_rvar (cfg, dreg, rtype);
6721         }
6722 }
6723
6724 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6725 static void
6726 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6727 {
6728         MonoInst *var = cfg->locals [local];
6729         if (COMPILE_SOFT_FLOAT (cfg)) {
6730                 MonoInst *store;
6731                 int reg = alloc_dreg (cfg, var->type);
6732                 emit_init_rvar (cfg, reg, type);
6733                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6734         } else {
6735                 if (init)
6736                         emit_init_rvar (cfg, var->dreg, type);
6737                 else
6738                         emit_dummy_init_rvar (cfg, var->dreg, type);
6739         }
6740 }
6741
6742 /*
6743  * inline_method:
6744  *
6745  *   Return the cost of inlining CMETHOD.
6746  */
6747 static int
6748 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6749                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6750 {
6751         MonoInst *ins, *rvar = NULL;
6752         MonoMethodHeader *cheader;
6753         MonoBasicBlock *ebblock, *sbblock;
6754         int i, costs;
6755         MonoMethod *prev_inlined_method;
6756         MonoInst **prev_locals, **prev_args;
6757         MonoType **prev_arg_types;
6758         guint prev_real_offset;
6759         GHashTable *prev_cbb_hash;
6760         MonoBasicBlock **prev_cil_offset_to_bb;
6761         MonoBasicBlock *prev_cbb;
6762         unsigned char* prev_cil_start;
6763         guint32 prev_cil_offset_to_bb_len;
6764         MonoMethod *prev_current_method;
6765         MonoGenericContext *prev_generic_context;
6766         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6767
6768         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6769
6770 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6771         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6772                 return 0;
6773 #endif
6774 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6775         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6776                 return 0;
6777 #endif
6778
6779         if (!fsig)
6780                 fsig = mono_method_signature (cmethod);
6781
6782         if (cfg->verbose_level > 2)
6783                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6784
6785         if (!cmethod->inline_info) {
6786                 cfg->stat_inlineable_methods++;
6787                 cmethod->inline_info = 1;
6788         }
6789
6790         /* allocate local variables */
6791         cheader = mono_method_get_header (cmethod);
6792
6793         if (cheader == NULL || mono_loader_get_last_error ()) {
6794                 MonoLoaderError *error = mono_loader_get_last_error ();
6795
6796                 if (cheader)
6797                         mono_metadata_free_mh (cheader);
6798                 if (inline_always && error)
6799                         mono_cfg_set_exception (cfg, error->exception_type);
6800
6801                 mono_loader_clear_error ();
6802                 return 0;
6803         }
6804
6805         /*Must verify before creating locals as it can cause the JIT to assert.*/
6806         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6807                 mono_metadata_free_mh (cheader);
6808                 return 0;
6809         }
6810
6811         /* allocate space to store the return value */
6812         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6813                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6814         }
6815
6816         prev_locals = cfg->locals;
6817         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6818         for (i = 0; i < cheader->num_locals; ++i)
6819                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6820
6821         /* allocate start and end blocks */
6822         /* This is needed so if the inline is aborted, we can clean up */
6823         NEW_BBLOCK (cfg, sbblock);
6824         sbblock->real_offset = real_offset;
6825
6826         NEW_BBLOCK (cfg, ebblock);
6827         ebblock->block_num = cfg->num_bblocks++;
6828         ebblock->real_offset = real_offset;
6829
6830         prev_args = cfg->args;
6831         prev_arg_types = cfg->arg_types;
6832         prev_inlined_method = cfg->inlined_method;
6833         cfg->inlined_method = cmethod;
6834         cfg->ret_var_set = FALSE;
6835         cfg->inline_depth ++;
6836         prev_real_offset = cfg->real_offset;
6837         prev_cbb_hash = cfg->cbb_hash;
6838         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6839         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6840         prev_cil_start = cfg->cil_start;
6841         prev_cbb = cfg->cbb;
6842         prev_current_method = cfg->current_method;
6843         prev_generic_context = cfg->generic_context;
6844         prev_ret_var_set = cfg->ret_var_set;
6845         prev_disable_inline = cfg->disable_inline;
6846
6847         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6848                 virtual = TRUE;
6849
6850         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6851
6852         ret_var_set = cfg->ret_var_set;
6853
6854         cfg->inlined_method = prev_inlined_method;
6855         cfg->real_offset = prev_real_offset;
6856         cfg->cbb_hash = prev_cbb_hash;
6857         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6858         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6859         cfg->cil_start = prev_cil_start;
6860         cfg->locals = prev_locals;
6861         cfg->args = prev_args;
6862         cfg->arg_types = prev_arg_types;
6863         cfg->current_method = prev_current_method;
6864         cfg->generic_context = prev_generic_context;
6865         cfg->ret_var_set = prev_ret_var_set;
6866         cfg->disable_inline = prev_disable_inline;
6867         cfg->inline_depth --;
6868
6869         if ((costs >= 0 && costs < 60) || inline_always) {
6870                 if (cfg->verbose_level > 2)
6871                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6872                 
6873                 cfg->stat_inlined_methods++;
6874
6875                 /* always add some code to avoid block split failures */
6876                 MONO_INST_NEW (cfg, ins, OP_NOP);
6877                 MONO_ADD_INS (prev_cbb, ins);
6878
6879                 prev_cbb->next_bb = sbblock;
6880                 link_bblock (cfg, prev_cbb, sbblock);
6881
6882                 /* 
6883                  * Get rid of the begin and end bblocks if possible to aid local
6884                  * optimizations.
6885                  */
6886                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6887
6888                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6889                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6890
6891                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6892                         MonoBasicBlock *prev = ebblock->in_bb [0];
6893                         mono_merge_basic_blocks (cfg, prev, ebblock);
6894                         cfg->cbb = prev;
6895                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6896                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6897                                 cfg->cbb = prev_cbb;
6898                         }
6899                 } else {
6900                         /* 
6901                          * Its possible that the rvar is set in some prev bblock, but not in others.
6902                          * (#1835).
6903                          */
6904                         if (rvar) {
6905                                 MonoBasicBlock *bb;
6906
6907                                 for (i = 0; i < ebblock->in_count; ++i) {
6908                                         bb = ebblock->in_bb [i];
6909
6910                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6911                                                 cfg->cbb = bb;
6912
6913                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6914                                         }
6915                                 }
6916                         }
6917
6918                         cfg->cbb = ebblock;
6919                 }
6920
6921                 if (out_cbb)
6922                         *out_cbb = cfg->cbb;
6923
6924                 if (rvar) {
6925                         /*
6926                          * If the inlined method contains only a throw, then the ret var is not 
6927                          * set, so set it to a dummy value.
6928                          */
6929                         if (!ret_var_set)
6930                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6931
6932                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6933                         *sp++ = ins;
6934                 }
6935                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6936                 return costs + 1;
6937         } else {
6938                 if (cfg->verbose_level > 2)
6939                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6940                 cfg->exception_type = MONO_EXCEPTION_NONE;
6941                 mono_loader_clear_error ();
6942
6943                 /* This gets rid of the newly added bblocks */
6944                 cfg->cbb = prev_cbb;
6945         }
6946         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6947         return 0;
6948 }
6949
6950 /*
6951  * Some of these comments may well be out-of-date.
6952  * Design decisions: we do a single pass over the IL code (and we do bblock 
6953  * splitting/merging in the few cases when it's required: a back jump to an IL
6954  * address that was not already seen as bblock starting point).
6955  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6956  * Complex operations are decomposed in simpler ones right away. We need to let the 
6957  * arch-specific code peek and poke inside this process somehow (except when the 
6958  * optimizations can take advantage of the full semantic info of coarse opcodes).
6959  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6960  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6961  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6962  * opcode with value bigger than OP_LAST.
6963  * At this point the IR can be handed over to an interpreter, a dumb code generator
6964  * or to the optimizing code generator that will translate it to SSA form.
6965  *
6966  * Profiling directed optimizations.
6967  * We may compile by default with few or no optimizations and instrument the code
6968  * or the user may indicate what methods to optimize the most either in a config file
6969  * or through repeated runs where the compiler applies offline the optimizations to 
6970  * each method and then decides if it was worth it.
6971  */
6972
6973 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6974 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6975 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6976 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6977 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6978 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6979 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6980 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6981
6982 /* offset from br.s -> br like opcodes */
6983 #define BIG_BRANCH_OFFSET 13
6984
6985 static gboolean
6986 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6987 {
6988         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6989
6990         return b == NULL || b == bb;
6991 }
6992
6993 static int
6994 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6995 {
6996         unsigned char *ip = start;
6997         unsigned char *target;
6998         int i;
6999         guint cli_addr;
7000         MonoBasicBlock *bblock;
7001         const MonoOpcode *opcode;
7002
7003         while (ip < end) {
7004                 cli_addr = ip - start;
7005                 i = mono_opcode_value ((const guint8 **)&ip, end);
7006                 if (i < 0)
7007                         UNVERIFIED;
7008                 opcode = &mono_opcodes [i];
7009                 switch (opcode->argument) {
7010                 case MonoInlineNone:
7011                         ip++; 
7012                         break;
7013                 case MonoInlineString:
7014                 case MonoInlineType:
7015                 case MonoInlineField:
7016                 case MonoInlineMethod:
7017                 case MonoInlineTok:
7018                 case MonoInlineSig:
7019                 case MonoShortInlineR:
7020                 case MonoInlineI:
7021                         ip += 5;
7022                         break;
7023                 case MonoInlineVar:
7024                         ip += 3;
7025                         break;
7026                 case MonoShortInlineVar:
7027                 case MonoShortInlineI:
7028                         ip += 2;
7029                         break;
7030                 case MonoShortInlineBrTarget:
7031                         target = start + cli_addr + 2 + (signed char)ip [1];
7032                         GET_BBLOCK (cfg, bblock, target);
7033                         ip += 2;
7034                         if (ip < end)
7035                                 GET_BBLOCK (cfg, bblock, ip);
7036                         break;
7037                 case MonoInlineBrTarget:
7038                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7039                         GET_BBLOCK (cfg, bblock, target);
7040                         ip += 5;
7041                         if (ip < end)
7042                                 GET_BBLOCK (cfg, bblock, ip);
7043                         break;
7044                 case MonoInlineSwitch: {
7045                         guint32 n = read32 (ip + 1);
7046                         guint32 j;
7047                         ip += 5;
7048                         cli_addr += 5 + 4 * n;
7049                         target = start + cli_addr;
7050                         GET_BBLOCK (cfg, bblock, target);
7051                         
7052                         for (j = 0; j < n; ++j) {
7053                                 target = start + cli_addr + (gint32)read32 (ip);
7054                                 GET_BBLOCK (cfg, bblock, target);
7055                                 ip += 4;
7056                         }
7057                         break;
7058                 }
7059                 case MonoInlineR:
7060                 case MonoInlineI8:
7061                         ip += 9;
7062                         break;
7063                 default:
7064                         g_assert_not_reached ();
7065                 }
7066
7067                 if (i == CEE_THROW) {
7068                         unsigned char *bb_start = ip - 1;
7069                         
7070                         /* Find the start of the bblock containing the throw */
7071                         bblock = NULL;
7072                         while ((bb_start >= start) && !bblock) {
7073                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7074                                 bb_start --;
7075                         }
7076                         if (bblock)
7077                                 bblock->out_of_line = 1;
7078                 }
7079         }
7080         return 0;
7081 unverified:
7082 exception_exit:
7083         *pos = ip;
7084         return 1;
7085 }
7086
7087 static inline MonoMethod *
7088 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7089 {
7090         MonoMethod *method;
7091
7092         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7093                 method = mono_method_get_wrapper_data (m, token);
7094                 if (context) {
7095                         MonoError error;
7096                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7097                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7098                 }
7099         } else {
7100                 method = mono_get_method_full (m->klass->image, token, klass, context);
7101         }
7102
7103         return method;
7104 }
7105
7106 static inline MonoMethod *
7107 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7108 {
7109         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7110
7111         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7112                 return NULL;
7113
7114         return method;
7115 }
7116
7117 static inline MonoClass*
7118 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7119 {
7120         MonoError error;
7121         MonoClass *klass;
7122
7123         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7124                 klass = mono_method_get_wrapper_data (method, token);
7125                 if (context)
7126                         klass = mono_class_inflate_generic_class (klass, context);
7127         } else {
7128                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7129                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7130         }
7131         if (klass)
7132                 mono_class_init (klass);
7133         return klass;
7134 }
7135
7136 static inline MonoMethodSignature*
7137 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7138 {
7139         MonoMethodSignature *fsig;
7140
7141         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7142                 MonoError error;
7143
7144                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7145                 if (context) {
7146                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7147                         // FIXME:
7148                         g_assert (mono_error_ok (&error));
7149                 }
7150         } else {
7151                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7152         }
7153         return fsig;
7154 }
7155
7156 /*
7157  * Returns TRUE if the JIT should abort inlining because "callee"
7158  * is influenced by security attributes.
7159  */
7160 static
7161 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7162 {
7163         guint32 result;
7164         
7165         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
7166                 return TRUE;
7167         }
7168         
7169         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
7170         if (result == MONO_JIT_SECURITY_OK)
7171                 return FALSE;
7172
7173         if (result == MONO_JIT_LINKDEMAND_ECMA) {
7174                 /* Generate code to throw a SecurityException before the actual call/link */
7175                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7176                 MonoInst *args [2];
7177
7178                 NEW_ICONST (cfg, args [0], 4);
7179                 NEW_METHODCONST (cfg, args [1], caller);
7180                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
7181         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
7182                  /* don't hide previous results */
7183                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
7184                 cfg->exception_data = result;
7185                 return TRUE;
7186         }
7187         
7188         return FALSE;
7189 }
7190
7191 static MonoMethod*
7192 throw_exception (void)
7193 {
7194         static MonoMethod *method = NULL;
7195
7196         if (!method) {
7197                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7198                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7199         }
7200         g_assert (method);
7201         return method;
7202 }
7203
7204 static void
7205 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7206 {
7207         MonoMethod *thrower = throw_exception ();
7208         MonoInst *args [1];
7209
7210         EMIT_NEW_PCONST (cfg, args [0], ex);
7211         mono_emit_method_call (cfg, thrower, args, NULL);
7212 }
7213
7214 /*
7215  * Return the original method is a wrapper is specified. We can only access 
7216  * the custom attributes from the original method.
7217  */
7218 static MonoMethod*
7219 get_original_method (MonoMethod *method)
7220 {
7221         if (method->wrapper_type == MONO_WRAPPER_NONE)
7222                 return method;
7223
7224         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7225         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7226                 return NULL;
7227
7228         /* in other cases we need to find the original method */
7229         return mono_marshal_method_from_wrapper (method);
7230 }
7231
7232 static void
7233 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
7234                                           MonoBasicBlock *bblock, unsigned char *ip)
7235 {
7236         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7237         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7238         if (ex)
7239                 emit_throw_exception (cfg, ex);
7240 }
7241
7242 static void
7243 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
7244                                          MonoBasicBlock *bblock, unsigned char *ip)
7245 {
7246         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7247         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7248         if (ex)
7249                 emit_throw_exception (cfg, ex);
7250 }
7251
7252 /*
7253  * Check that the IL instructions at ip are the array initialization
7254  * sequence and return the pointer to the data and the size.
7255  */
7256 static const char*
7257 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7258 {
7259         /*
7260          * newarr[System.Int32]
7261          * dup
7262          * ldtoken field valuetype ...
7263          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7264          */
7265         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7266                 MonoError error;
7267                 guint32 token = read32 (ip + 7);
7268                 guint32 field_token = read32 (ip + 2);
7269                 guint32 field_index = field_token & 0xffffff;
7270                 guint32 rva;
7271                 const char *data_ptr;
7272                 int size = 0;
7273                 MonoMethod *cmethod;
7274                 MonoClass *dummy_class;
7275                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7276                 int dummy_align;
7277
7278                 if (!field) {
7279                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7280                         return NULL;
7281                 }
7282
7283                 *out_field_token = field_token;
7284
7285                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7286                 if (!cmethod)
7287                         return NULL;
7288                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7289                         return NULL;
7290                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7291                 case MONO_TYPE_BOOLEAN:
7292                 case MONO_TYPE_I1:
7293                 case MONO_TYPE_U1:
7294                         size = 1; break;
7295                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7296 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7297                 case MONO_TYPE_CHAR:
7298                 case MONO_TYPE_I2:
7299                 case MONO_TYPE_U2:
7300                         size = 2; break;
7301                 case MONO_TYPE_I4:
7302                 case MONO_TYPE_U4:
7303                 case MONO_TYPE_R4:
7304                         size = 4; break;
7305                 case MONO_TYPE_R8:
7306                 case MONO_TYPE_I8:
7307                 case MONO_TYPE_U8:
7308                         size = 8; break;
7309 #endif
7310                 default:
7311                         return NULL;
7312                 }
7313                 size *= len;
7314                 if (size > mono_type_size (field->type, &dummy_align))
7315                     return NULL;
7316                 *out_size = size;
7317                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7318                 if (!image_is_dynamic (method->klass->image)) {
7319                         field_index = read32 (ip + 2) & 0xffffff;
7320                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7321                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7322                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7323                         /* for aot code we do the lookup on load */
7324                         if (aot && data_ptr)
7325                                 return GUINT_TO_POINTER (rva);
7326                 } else {
7327                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7328                         g_assert (!aot);
7329                         data_ptr = mono_field_get_data (field);
7330                 }
7331                 return data_ptr;
7332         }
7333         return NULL;
7334 }
7335
7336 static void
7337 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7338 {
7339         char *method_fname = mono_method_full_name (method, TRUE);
7340         char *method_code;
7341         MonoMethodHeader *header = mono_method_get_header (method);
7342
7343         if (header->code_size == 0)
7344                 method_code = g_strdup ("method body is empty.");
7345         else
7346                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7347         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7348         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7349         g_free (method_fname);
7350         g_free (method_code);
7351         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7352 }
7353
7354 static void
7355 set_exception_object (MonoCompile *cfg, MonoException *exception)
7356 {
7357         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7358         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7359         cfg->exception_ptr = exception;
7360 }
7361
7362 static void
7363 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7364 {
7365         MonoInst *ins;
7366         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7367         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7368                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7369                 /* Optimize reg-reg moves away */
7370                 /* 
7371                  * Can't optimize other opcodes, since sp[0] might point to
7372                  * the last ins of a decomposed opcode.
7373                  */
7374                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7375         } else {
7376                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7377         }
7378 }
7379
7380 /*
7381  * ldloca inhibits many optimizations so try to get rid of it in common
7382  * cases.
7383  */
7384 static inline unsigned char *
7385 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7386 {
7387         int local, token;
7388         MonoClass *klass;
7389         MonoType *type;
7390
7391         if (size == 1) {
7392                 local = ip [1];
7393                 ip += 2;
7394         } else {
7395                 local = read16 (ip + 2);
7396                 ip += 4;
7397         }
7398         
7399         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7400                 /* From the INITOBJ case */
7401                 token = read32 (ip + 2);
7402                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7403                 CHECK_TYPELOAD (klass);
7404                 type = mini_get_underlying_type (cfg, &klass->byval_arg);
7405                 emit_init_local (cfg, local, type, TRUE);
7406                 return ip + 6;
7407         }
7408  exception_exit:
7409         return NULL;
7410 }
7411
7412 static gboolean
7413 is_exception_class (MonoClass *class)
7414 {
7415         while (class) {
7416                 if (class == mono_defaults.exception_class)
7417                         return TRUE;
7418                 class = class->parent;
7419         }
7420         return FALSE;
7421 }
7422
7423 /*
7424  * is_jit_optimizer_disabled:
7425  *
7426  *   Determine whenever M's assembly has a DebuggableAttribute with the
7427  * IsJITOptimizerDisabled flag set.
7428  */
7429 static gboolean
7430 is_jit_optimizer_disabled (MonoMethod *m)
7431 {
7432         MonoAssembly *ass = m->klass->image->assembly;
7433         MonoCustomAttrInfo* attrs;
7434         static MonoClass *klass;
7435         int i;
7436         gboolean val = FALSE;
7437
7438         g_assert (ass);
7439         if (ass->jit_optimizer_disabled_inited)
7440                 return ass->jit_optimizer_disabled;
7441
7442         if (!klass)
7443                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7444         if (!klass) {
7445                 /* Linked away */
7446                 ass->jit_optimizer_disabled = FALSE;
7447                 mono_memory_barrier ();
7448                 ass->jit_optimizer_disabled_inited = TRUE;
7449                 return FALSE;
7450         }
7451
7452         attrs = mono_custom_attrs_from_assembly (ass);
7453         if (attrs) {
7454                 for (i = 0; i < attrs->num_attrs; ++i) {
7455                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7456                         const gchar *p;
7457                         MonoMethodSignature *sig;
7458
7459                         if (!attr->ctor || attr->ctor->klass != klass)
7460                                 continue;
7461                         /* Decode the attribute. See reflection.c */
7462                         p = (const char*)attr->data;
7463                         g_assert (read16 (p) == 0x0001);
7464                         p += 2;
7465
7466                         // FIXME: Support named parameters
7467                         sig = mono_method_signature (attr->ctor);
7468                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7469                                 continue;
7470                         /* Two boolean arguments */
7471                         p ++;
7472                         val = *p;
7473                 }
7474                 mono_custom_attrs_free (attrs);
7475         }
7476
7477         ass->jit_optimizer_disabled = val;
7478         mono_memory_barrier ();
7479         ass->jit_optimizer_disabled_inited = TRUE;
7480
7481         return val;
7482 }
7483
7484 static gboolean
7485 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7486 {
7487         gboolean supported_tail_call;
7488         int i;
7489
7490 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7491         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7492 #else
7493         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7494 #endif
7495
7496         for (i = 0; i < fsig->param_count; ++i) {
7497                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7498                         /* These can point to the current method's stack */
7499                         supported_tail_call = FALSE;
7500         }
7501         if (fsig->hasthis && cmethod->klass->valuetype)
7502                 /* this might point to the current method's stack */
7503                 supported_tail_call = FALSE;
7504         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7505                 supported_tail_call = FALSE;
7506         if (cfg->method->save_lmf)
7507                 supported_tail_call = FALSE;
7508         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7509                 supported_tail_call = FALSE;
7510         if (call_opcode != CEE_CALL)
7511                 supported_tail_call = FALSE;
7512
7513         /* Debugging support */
7514 #if 0
7515         if (supported_tail_call) {
7516                 if (!mono_debug_count ())
7517                         supported_tail_call = FALSE;
7518         }
7519 #endif
7520
7521         return supported_tail_call;
7522 }
7523
7524 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7525  * it to the thread local value based on the tls_offset field. Every other kind of access to
7526  * the field causes an assert.
7527  */
7528 static gboolean
7529 is_magic_tls_access (MonoClassField *field)
7530 {
7531         if (strcmp (field->name, "tlsdata"))
7532                 return FALSE;
7533         if (strcmp (field->parent->name, "ThreadLocal`1"))
7534                 return FALSE;
7535         return field->parent->image == mono_defaults.corlib;
7536 }
7537
7538 /* emits the code needed to access a managed tls var (like ThreadStatic)
7539  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7540  * pointer for the current thread.
7541  * Returns the MonoInst* representing the address of the tls var.
7542  */
7543 static MonoInst*
7544 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7545 {
7546         MonoInst *addr;
7547         int static_data_reg, array_reg, dreg;
7548         int offset2_reg, idx_reg;
7549         // inlined access to the tls data
7550         // idx = (offset >> 24) - 1;
7551         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7552         static_data_reg = alloc_ireg (cfg);
7553         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7554         idx_reg = alloc_ireg (cfg);
7555         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7556         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7557         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7558         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7559         array_reg = alloc_ireg (cfg);
7560         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7561         offset2_reg = alloc_ireg (cfg);
7562         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7563         dreg = alloc_ireg (cfg);
7564         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7565         return addr;
7566 }
7567
7568 /*
7569  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7570  * this address is cached per-method in cached_tls_addr.
7571  */
7572 static MonoInst*
7573 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7574 {
7575         MonoInst *load, *addr, *temp, *store, *thread_ins;
7576         MonoClassField *offset_field;
7577
7578         if (*cached_tls_addr) {
7579                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7580                 return addr;
7581         }
7582         thread_ins = mono_get_thread_intrinsic (cfg);
7583         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7584
7585         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7586         if (thread_ins) {
7587                 MONO_ADD_INS (cfg->cbb, thread_ins);
7588         } else {
7589                 MonoMethod *thread_method;
7590                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7591                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7592         }
7593         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7594         addr->klass = mono_class_from_mono_type (tls_field->type);
7595         addr->type = STACK_MP;
7596         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7597         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7598
7599         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7600         return addr;
7601 }
7602
7603 /*
7604  * handle_ctor_call:
7605  *
7606  *   Handle calls made to ctors from NEWOBJ opcodes.
7607  *
7608  *   REF_BBLOCK will point to the current bblock after the call.
7609  */
7610 static void
7611 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7612                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7613 {
7614         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7615         MonoBasicBlock *bblock = *ref_bblock;
7616
7617         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7618                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7619                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7620                         mono_class_vtable (cfg->domain, cmethod->klass);
7621                         CHECK_TYPELOAD (cmethod->klass);
7622
7623                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7624                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7625                 } else {
7626                         if (context_used) {
7627                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7628                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7629                         } else {
7630                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7631
7632                                 CHECK_TYPELOAD (cmethod->klass);
7633                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7634                         }
7635                 }
7636         }
7637
7638         /* Avoid virtual calls to ctors if possible */
7639         if (mono_class_is_marshalbyref (cmethod->klass))
7640                 callvirt_this_arg = sp [0];
7641
7642         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7643                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7644                 CHECK_CFG_EXCEPTION;
7645         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7646                            mono_method_check_inlining (cfg, cmethod) &&
7647                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7648                 int costs;
7649
7650                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7651                         cfg->real_offset += 5;
7652
7653                         *inline_costs += costs - 5;
7654                         *ref_bblock = bblock;
7655                 } else {
7656                         INLINE_FAILURE ("inline failure");
7657                         // FIXME-VT: Clean this up
7658                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7659                                 GSHAREDVT_FAILURE(*ip);
7660                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7661                 }
7662         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7663                 MonoInst *addr;
7664
7665                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7666                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7667         } else if (context_used &&
7668                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7669                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7670                 MonoInst *cmethod_addr;
7671
7672                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7673
7674                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7675                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7676
7677                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7678         } else {
7679                 INLINE_FAILURE ("ctor call");
7680                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7681                                                                                   callvirt_this_arg, NULL, vtable_arg);
7682         }
7683  exception_exit:
7684         return;
7685 }
7686
7687 /*
7688  * mono_method_to_ir:
7689  *
7690  *   Translate the .net IL into linear IR.
7691  */
7692 int
7693 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7694                    MonoInst *return_var, MonoInst **inline_args, 
7695                    guint inline_offset, gboolean is_virtual_call)
7696 {
7697         MonoError error;
7698         MonoInst *ins, **sp, **stack_start;
7699         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7700         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7701         MonoMethod *cmethod, *method_definition;
7702         MonoInst **arg_array;
7703         MonoMethodHeader *header;
7704         MonoImage *image;
7705         guint32 token, ins_flag;
7706         MonoClass *klass;
7707         MonoClass *constrained_class = NULL;
7708         unsigned char *ip, *end, *target, *err_pos;
7709         MonoMethodSignature *sig;
7710         MonoGenericContext *generic_context = NULL;
7711         MonoGenericContainer *generic_container = NULL;
7712         MonoType **param_types;
7713         int i, n, start_new_bblock, dreg;
7714         int num_calls = 0, inline_costs = 0;
7715         int breakpoint_id = 0;
7716         guint num_args;
7717         MonoBoolean security, pinvoke;
7718         MonoSecurityManager* secman = NULL;
7719         MonoDeclSecurityActions actions;
7720         GSList *class_inits = NULL;
7721         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7722         int context_used;
7723         gboolean init_locals, seq_points, skip_dead_blocks;
7724         gboolean sym_seq_points = FALSE;
7725         MonoInst *cached_tls_addr = NULL;
7726         MonoDebugMethodInfo *minfo;
7727         MonoBitSet *seq_point_locs = NULL;
7728         MonoBitSet *seq_point_set_locs = NULL;
7729
7730         cfg->disable_inline = is_jit_optimizer_disabled (method);
7731
7732         /* serialization and xdomain stuff may need access to private fields and methods */
7733         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7734         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7735         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7736         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7737         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7738         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7739
7740         dont_verify |= mono_security_smcs_hack_enabled ();
7741
7742         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7743         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7744         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7745         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7746         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7747
7748         image = method->klass->image;
7749         header = mono_method_get_header (method);
7750         if (!header) {
7751                 MonoLoaderError *error;
7752
7753                 if ((error = mono_loader_get_last_error ())) {
7754                         mono_cfg_set_exception (cfg, error->exception_type);
7755                 } else {
7756                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7757                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7758                 }
7759                 goto exception_exit;
7760         }
7761         generic_container = mono_method_get_generic_container (method);
7762         sig = mono_method_signature (method);
7763         num_args = sig->hasthis + sig->param_count;
7764         ip = (unsigned char*)header->code;
7765         cfg->cil_start = ip;
7766         end = ip + header->code_size;
7767         cfg->stat_cil_code_size += header->code_size;
7768
7769         seq_points = cfg->gen_seq_points && cfg->method == method;
7770 #ifdef PLATFORM_ANDROID
7771         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7772 #endif
7773
7774         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7775                 /* We could hit a seq point before attaching to the JIT (#8338) */
7776                 seq_points = FALSE;
7777         }
7778
7779         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7780                 minfo = mono_debug_lookup_method (method);
7781                 if (minfo) {
7782                         int i, n_il_offsets;
7783                         int *il_offsets;
7784                         int *line_numbers;
7785
7786                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7787                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7788                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7789                         sym_seq_points = TRUE;
7790                         for (i = 0; i < n_il_offsets; ++i) {
7791                                 if (il_offsets [i] < header->code_size)
7792                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7793                         }
7794                         g_free (il_offsets);
7795                         g_free (line_numbers);
7796                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7797                         /* Methods without line number info like auto-generated property accessors */
7798                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7799                         seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7800                         sym_seq_points = TRUE;
7801                 }
7802         }
7803
7804         /* 
7805          * Methods without init_locals set could cause asserts in various passes
7806          * (#497220). To work around this, we emit dummy initialization opcodes
7807          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7808          * on some platforms.
7809          */
7810         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7811                 init_locals = header->init_locals;
7812         else
7813                 init_locals = TRUE;
7814
7815         method_definition = method;
7816         while (method_definition->is_inflated) {
7817                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7818                 method_definition = imethod->declaring;
7819         }
7820
7821         /* SkipVerification is not allowed if core-clr is enabled */
7822         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7823                 dont_verify = TRUE;
7824                 dont_verify_stloc = TRUE;
7825         }
7826
7827         if (sig->is_inflated)
7828                 generic_context = mono_method_get_context (method);
7829         else if (generic_container)
7830                 generic_context = &generic_container->context;
7831         cfg->generic_context = generic_context;
7832
7833         if (!cfg->generic_sharing_context)
7834                 g_assert (!sig->has_type_parameters);
7835
7836         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7837                 g_assert (method->is_inflated);
7838                 g_assert (mono_method_get_context (method)->method_inst);
7839         }
7840         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7841                 g_assert (sig->generic_param_count);
7842
7843         if (cfg->method == method) {
7844                 cfg->real_offset = 0;
7845         } else {
7846                 cfg->real_offset = inline_offset;
7847         }
7848
7849         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7850         cfg->cil_offset_to_bb_len = header->code_size;
7851
7852         cfg->current_method = method;
7853
7854         if (cfg->verbose_level > 2)
7855                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7856
7857         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7858         if (sig->hasthis)
7859                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7860         for (n = 0; n < sig->param_count; ++n)
7861                 param_types [n + sig->hasthis] = sig->params [n];
7862         cfg->arg_types = param_types;
7863
7864         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7865         if (cfg->method == method) {
7866
7867                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7868                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7869
7870                 /* ENTRY BLOCK */
7871                 NEW_BBLOCK (cfg, start_bblock);
7872                 cfg->bb_entry = start_bblock;
7873                 start_bblock->cil_code = NULL;
7874                 start_bblock->cil_length = 0;
7875 #if defined(__native_client_codegen__)
7876                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7877                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7878                 MONO_ADD_INS (start_bblock, ins);
7879 #endif
7880
7881                 /* EXIT BLOCK */
7882                 NEW_BBLOCK (cfg, end_bblock);
7883                 cfg->bb_exit = end_bblock;
7884                 end_bblock->cil_code = NULL;
7885                 end_bblock->cil_length = 0;
7886                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7887                 g_assert (cfg->num_bblocks == 2);
7888
7889                 arg_array = cfg->args;
7890
7891                 if (header->num_clauses) {
7892                         cfg->spvars = g_hash_table_new (NULL, NULL);
7893                         cfg->exvars = g_hash_table_new (NULL, NULL);
7894                 }
7895                 /* handle exception clauses */
7896                 for (i = 0; i < header->num_clauses; ++i) {
7897                         MonoBasicBlock *try_bb;
7898                         MonoExceptionClause *clause = &header->clauses [i];
7899                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7900                         try_bb->real_offset = clause->try_offset;
7901                         try_bb->try_start = TRUE;
7902                         try_bb->region = ((i + 1) << 8) | clause->flags;
7903                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7904                         tblock->real_offset = clause->handler_offset;
7905                         tblock->flags |= BB_EXCEPTION_HANDLER;
7906
7907                         /*
7908                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7909                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7910                          */
7911                         if (COMPILE_LLVM (cfg))
7912                                 link_bblock (cfg, try_bb, tblock);
7913
7914                         if (*(ip + clause->handler_offset) == CEE_POP)
7915                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7916
7917                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7918                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7919                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7920                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7921                                 MONO_ADD_INS (tblock, ins);
7922
7923                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7924                                         /* finally clauses already have a seq point */
7925                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7926                                         MONO_ADD_INS (tblock, ins);
7927                                 }
7928
7929                                 /* todo: is a fault block unsafe to optimize? */
7930                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7931                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7932                         }
7933
7934
7935                         /*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);
7936                           while (p < end) {
7937                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7938                           }*/
7939                         /* catch and filter blocks get the exception object on the stack */
7940                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7941                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7942                                 MonoInst *dummy_use;
7943
7944                                 /* mostly like handle_stack_args (), but just sets the input args */
7945                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7946                                 tblock->in_scount = 1;
7947                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7948                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7949
7950                                 /* 
7951                                  * Add a dummy use for the exvar so its liveness info will be
7952                                  * correct.
7953                                  */
7954                                 cfg->cbb = tblock;
7955                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7956                                 
7957                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7958                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7959                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7960                                         tblock->real_offset = clause->data.filter_offset;
7961                                         tblock->in_scount = 1;
7962                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7963                                         /* The filter block shares the exvar with the handler block */
7964                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7965                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7966                                         MONO_ADD_INS (tblock, ins);
7967                                 }
7968                         }
7969
7970                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7971                                         clause->data.catch_class &&
7972                                         cfg->generic_sharing_context &&
7973                                         mono_class_check_context_used (clause->data.catch_class)) {
7974                                 /*
7975                                  * In shared generic code with catch
7976                                  * clauses containing type variables
7977                                  * the exception handling code has to
7978                                  * be able to get to the rgctx.
7979                                  * Therefore we have to make sure that
7980                                  * the vtable/mrgctx argument (for
7981                                  * static or generic methods) or the
7982                                  * "this" argument (for non-static
7983                                  * methods) are live.
7984                                  */
7985                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7986                                                 mini_method_get_context (method)->method_inst ||
7987                                                 method->klass->valuetype) {
7988                                         mono_get_vtable_var (cfg);
7989                                 } else {
7990                                         MonoInst *dummy_use;
7991
7992                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7993                                 }
7994                         }
7995                 }
7996         } else {
7997                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7998                 cfg->cbb = start_bblock;
7999                 cfg->args = arg_array;
8000                 mono_save_args (cfg, sig, inline_args);
8001         }
8002
8003         /* FIRST CODE BLOCK */
8004         NEW_BBLOCK (cfg, bblock);
8005         bblock->cil_code = ip;
8006         cfg->cbb = bblock;
8007         cfg->ip = ip;
8008
8009         ADD_BBLOCK (cfg, bblock);
8010
8011         if (cfg->method == method) {
8012                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8013                 if (breakpoint_id) {
8014                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8015                         MONO_ADD_INS (bblock, ins);
8016                 }
8017         }
8018
8019         if (mono_security_cas_enabled ())
8020                 secman = mono_security_manager_get_methods ();
8021
8022         security = (secman && mono_security_method_has_declsec (method));
8023         /* at this point having security doesn't mean we have any code to generate */
8024         if (security && (cfg->method == method)) {
8025                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
8026                  * And we do not want to enter the next section (with allocation) if we
8027                  * have nothing to generate */
8028                 security = mono_declsec_get_demands (method, &actions);
8029         }
8030
8031         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
8032         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
8033         if (pinvoke) {
8034                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8035                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8036                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
8037
8038                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
8039                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8040                                 pinvoke = FALSE;
8041                         }
8042                         if (custom)
8043                                 mono_custom_attrs_free (custom);
8044
8045                         if (pinvoke) {
8046                                 custom = mono_custom_attrs_from_class (wrapped->klass);
8047                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8048                                         pinvoke = FALSE;
8049                                 }
8050                                 if (custom)
8051                                         mono_custom_attrs_free (custom);
8052                         }
8053                 } else {
8054                         /* not a P/Invoke after all */
8055                         pinvoke = FALSE;
8056                 }
8057         }
8058         
8059         /* we use a separate basic block for the initialization code */
8060         NEW_BBLOCK (cfg, init_localsbb);
8061         cfg->bb_init = init_localsbb;
8062         init_localsbb->real_offset = cfg->real_offset;
8063         start_bblock->next_bb = init_localsbb;
8064         init_localsbb->next_bb = bblock;
8065         link_bblock (cfg, start_bblock, init_localsbb);
8066         link_bblock (cfg, init_localsbb, bblock);
8067                 
8068         cfg->cbb = init_localsbb;
8069
8070         if (cfg->gsharedvt && cfg->method == method) {
8071                 MonoGSharedVtMethodInfo *info;
8072                 MonoInst *var, *locals_var;
8073                 int dreg;
8074
8075                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8076                 info->method = cfg->method;
8077                 info->count_entries = 16;
8078                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8079                 cfg->gsharedvt_info = info;
8080
8081                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8082                 /* prevent it from being register allocated */
8083                 //var->flags |= MONO_INST_VOLATILE;
8084                 cfg->gsharedvt_info_var = var;
8085
8086                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8087                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8088
8089                 /* Allocate locals */
8090                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8091                 /* prevent it from being register allocated */
8092                 //locals_var->flags |= MONO_INST_VOLATILE;
8093                 cfg->gsharedvt_locals_var = locals_var;
8094
8095                 dreg = alloc_ireg (cfg);
8096                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8097
8098                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8099                 ins->dreg = locals_var->dreg;
8100                 ins->sreg1 = dreg;
8101                 MONO_ADD_INS (cfg->cbb, ins);
8102                 cfg->gsharedvt_locals_var_ins = ins;
8103                 
8104                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8105                 /*
8106                 if (init_locals)
8107                         ins->flags |= MONO_INST_INIT;
8108                 */
8109         }
8110
8111         /* at this point we know, if security is TRUE, that some code needs to be generated */
8112         if (security && (cfg->method == method)) {
8113                 MonoInst *args [2];
8114
8115                 cfg->stat_cas_demand_generation++;
8116
8117                 if (actions.demand.blob) {
8118                         /* Add code for SecurityAction.Demand */
8119                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
8120                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
8121                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8122                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8123                 }
8124                 if (actions.noncasdemand.blob) {
8125                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
8126                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
8127                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
8128                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
8129                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8130                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8131                 }
8132                 if (actions.demandchoice.blob) {
8133                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
8134                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
8135                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
8136                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
8137                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
8138                 }
8139         }
8140
8141         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
8142         if (pinvoke) {
8143                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
8144         }
8145
8146         if (mono_security_core_clr_enabled ()) {
8147                 /* check if this is native code, e.g. an icall or a p/invoke */
8148                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8149                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8150                         if (wrapped) {
8151                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8152                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8153
8154                                 /* if this ia a native call then it can only be JITted from platform code */
8155                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8156                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8157                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8158                                                         mono_get_exception_method_access ();
8159                                                 emit_throw_exception (cfg, ex);
8160                                         }
8161                                 }
8162                         }
8163                 }
8164         }
8165
8166         CHECK_CFG_EXCEPTION;
8167
8168         if (header->code_size == 0)
8169                 UNVERIFIED;
8170
8171         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8172                 ip = err_pos;
8173                 UNVERIFIED;
8174         }
8175
8176         if (cfg->method == method)
8177                 mono_debug_init_method (cfg, bblock, breakpoint_id);
8178
8179         for (n = 0; n < header->num_locals; ++n) {
8180                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8181                         UNVERIFIED;
8182         }
8183         class_inits = NULL;
8184
8185         /* We force the vtable variable here for all shared methods
8186            for the possibility that they might show up in a stack
8187            trace where their exact instantiation is needed. */
8188         if (cfg->generic_sharing_context && method == cfg->method) {
8189                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8190                                 mini_method_get_context (method)->method_inst ||
8191                                 method->klass->valuetype) {
8192                         mono_get_vtable_var (cfg);
8193                 } else {
8194                         /* FIXME: Is there a better way to do this?
8195                            We need the variable live for the duration
8196                            of the whole method. */
8197                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8198                 }
8199         }
8200
8201         /* add a check for this != NULL to inlined methods */
8202         if (is_virtual_call) {
8203                 MonoInst *arg_ins;
8204
8205                 NEW_ARGLOAD (cfg, arg_ins, 0);
8206                 MONO_ADD_INS (cfg->cbb, arg_ins);
8207                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8208         }
8209
8210         skip_dead_blocks = !dont_verify;
8211         if (skip_dead_blocks) {
8212                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8213                 CHECK_CFG_ERROR;
8214                 g_assert (bb);
8215         }
8216
8217         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8218         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8219
8220         ins_flag = 0;
8221         start_new_bblock = 0;
8222         cfg->cbb = bblock;
8223         while (ip < end) {
8224                 if (cfg->method == method)
8225                         cfg->real_offset = ip - header->code;
8226                 else
8227                         cfg->real_offset = inline_offset;
8228                 cfg->ip = ip;
8229
8230                 context_used = 0;
8231                 
8232                 if (start_new_bblock) {
8233                         bblock->cil_length = ip - bblock->cil_code;
8234                         if (start_new_bblock == 2) {
8235                                 g_assert (ip == tblock->cil_code);
8236                         } else {
8237                                 GET_BBLOCK (cfg, tblock, ip);
8238                         }
8239                         bblock->next_bb = tblock;
8240                         bblock = tblock;
8241                         cfg->cbb = bblock;
8242                         start_new_bblock = 0;
8243                         for (i = 0; i < bblock->in_scount; ++i) {
8244                                 if (cfg->verbose_level > 3)
8245                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8246                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8247                                 *sp++ = ins;
8248                         }
8249                         if (class_inits)
8250                                 g_slist_free (class_inits);
8251                         class_inits = NULL;
8252                 } else {
8253                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
8254                                 link_bblock (cfg, bblock, tblock);
8255                                 if (sp != stack_start) {
8256                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8257                                         sp = stack_start;
8258                                         CHECK_UNVERIFIABLE (cfg);
8259                                 }
8260                                 bblock->next_bb = tblock;
8261                                 bblock = tblock;
8262                                 cfg->cbb = bblock;
8263                                 for (i = 0; i < bblock->in_scount; ++i) {
8264                                         if (cfg->verbose_level > 3)
8265                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8266                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8267                                         *sp++ = ins;
8268                                 }
8269                                 g_slist_free (class_inits);
8270                                 class_inits = NULL;
8271                         }
8272                 }
8273
8274                 if (skip_dead_blocks) {
8275                         int ip_offset = ip - header->code;
8276
8277                         if (ip_offset == bb->end)
8278                                 bb = bb->next;
8279
8280                         if (bb->dead) {
8281                                 int op_size = mono_opcode_size (ip, end);
8282                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8283
8284                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8285
8286                                 if (ip_offset + op_size == bb->end) {
8287                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8288                                         MONO_ADD_INS (bblock, ins);
8289                                         start_new_bblock = 1;
8290                                 }
8291
8292                                 ip += op_size;
8293                                 continue;
8294                         }
8295                 }
8296                 /*
8297                  * Sequence points are points where the debugger can place a breakpoint.
8298                  * Currently, we generate these automatically at points where the IL
8299                  * stack is empty.
8300                  */
8301                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8302                         /*
8303                          * Make methods interruptable at the beginning, and at the targets of
8304                          * backward branches.
8305                          * Also, do this at the start of every bblock in methods with clauses too,
8306                          * to be able to handle instructions with inprecise control flow like
8307                          * throw/endfinally.
8308                          * Backward branches are handled at the end of method-to-ir ().
8309                          */
8310                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8311
8312                         /* Avoid sequence points on empty IL like .volatile */
8313                         // FIXME: Enable this
8314                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8315                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8316                         if (sp != stack_start)
8317                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8318                         MONO_ADD_INS (cfg->cbb, ins);
8319
8320                         if (sym_seq_points)
8321                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8322                 }
8323
8324                 bblock->real_offset = cfg->real_offset;
8325
8326                 if ((cfg->method == method) && cfg->coverage_info) {
8327                         guint32 cil_offset = ip - header->code;
8328                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8329
8330                         /* TODO: Use an increment here */
8331 #if defined(TARGET_X86)
8332                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8333                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8334                         ins->inst_imm = 1;
8335                         MONO_ADD_INS (cfg->cbb, ins);
8336 #else
8337                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8338                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8339 #endif
8340                 }
8341
8342                 if (cfg->verbose_level > 3)
8343                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8344
8345                 switch (*ip) {
8346                 case CEE_NOP:
8347                         if (seq_points && !sym_seq_points && sp != stack_start) {
8348                                 /*
8349                                  * The C# compiler uses these nops to notify the JIT that it should
8350                                  * insert seq points.
8351                                  */
8352                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8353                                 MONO_ADD_INS (cfg->cbb, ins);
8354                         }
8355                         if (cfg->keep_cil_nops)
8356                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8357                         else
8358                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8359                         ip++;
8360                         MONO_ADD_INS (bblock, ins);
8361                         break;
8362                 case CEE_BREAK:
8363                         if (should_insert_brekpoint (cfg->method)) {
8364                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8365                         } else {
8366                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8367                         }
8368                         ip++;
8369                         MONO_ADD_INS (bblock, ins);
8370                         break;
8371                 case CEE_LDARG_0:
8372                 case CEE_LDARG_1:
8373                 case CEE_LDARG_2:
8374                 case CEE_LDARG_3:
8375                         CHECK_STACK_OVF (1);
8376                         n = (*ip)-CEE_LDARG_0;
8377                         CHECK_ARG (n);
8378                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8379                         ip++;
8380                         *sp++ = ins;
8381                         break;
8382                 case CEE_LDLOC_0:
8383                 case CEE_LDLOC_1:
8384                 case CEE_LDLOC_2:
8385                 case CEE_LDLOC_3:
8386                         CHECK_STACK_OVF (1);
8387                         n = (*ip)-CEE_LDLOC_0;
8388                         CHECK_LOCAL (n);
8389                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8390                         ip++;
8391                         *sp++ = ins;
8392                         break;
8393                 case CEE_STLOC_0:
8394                 case CEE_STLOC_1:
8395                 case CEE_STLOC_2:
8396                 case CEE_STLOC_3: {
8397                         CHECK_STACK (1);
8398                         n = (*ip)-CEE_STLOC_0;
8399                         CHECK_LOCAL (n);
8400                         --sp;
8401                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8402                                 UNVERIFIED;
8403                         emit_stloc_ir (cfg, sp, header, n);
8404                         ++ip;
8405                         inline_costs += 1;
8406                         break;
8407                         }
8408                 case CEE_LDARG_S:
8409                         CHECK_OPSIZE (2);
8410                         CHECK_STACK_OVF (1);
8411                         n = ip [1];
8412                         CHECK_ARG (n);
8413                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8414                         *sp++ = ins;
8415                         ip += 2;
8416                         break;
8417                 case CEE_LDARGA_S:
8418                         CHECK_OPSIZE (2);
8419                         CHECK_STACK_OVF (1);
8420                         n = ip [1];
8421                         CHECK_ARG (n);
8422                         NEW_ARGLOADA (cfg, ins, n);
8423                         MONO_ADD_INS (cfg->cbb, ins);
8424                         *sp++ = ins;
8425                         ip += 2;
8426                         break;
8427                 case CEE_STARG_S:
8428                         CHECK_OPSIZE (2);
8429                         CHECK_STACK (1);
8430                         --sp;
8431                         n = ip [1];
8432                         CHECK_ARG (n);
8433                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8434                                 UNVERIFIED;
8435                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8436                         ip += 2;
8437                         break;
8438                 case CEE_LDLOC_S:
8439                         CHECK_OPSIZE (2);
8440                         CHECK_STACK_OVF (1);
8441                         n = ip [1];
8442                         CHECK_LOCAL (n);
8443                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8444                         *sp++ = ins;
8445                         ip += 2;
8446                         break;
8447                 case CEE_LDLOCA_S: {
8448                         unsigned char *tmp_ip;
8449                         CHECK_OPSIZE (2);
8450                         CHECK_STACK_OVF (1);
8451                         CHECK_LOCAL (ip [1]);
8452
8453                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8454                                 ip = tmp_ip;
8455                                 inline_costs += 1;
8456                                 break;
8457                         }
8458
8459                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8460                         *sp++ = ins;
8461                         ip += 2;
8462                         break;
8463                 }
8464                 case CEE_STLOC_S:
8465                         CHECK_OPSIZE (2);
8466                         CHECK_STACK (1);
8467                         --sp;
8468                         CHECK_LOCAL (ip [1]);
8469                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8470                                 UNVERIFIED;
8471                         emit_stloc_ir (cfg, sp, header, ip [1]);
8472                         ip += 2;
8473                         inline_costs += 1;
8474                         break;
8475                 case CEE_LDNULL:
8476                         CHECK_STACK_OVF (1);
8477                         EMIT_NEW_PCONST (cfg, ins, NULL);
8478                         ins->type = STACK_OBJ;
8479                         ++ip;
8480                         *sp++ = ins;
8481                         break;
8482                 case CEE_LDC_I4_M1:
8483                         CHECK_STACK_OVF (1);
8484                         EMIT_NEW_ICONST (cfg, ins, -1);
8485                         ++ip;
8486                         *sp++ = ins;
8487                         break;
8488                 case CEE_LDC_I4_0:
8489                 case CEE_LDC_I4_1:
8490                 case CEE_LDC_I4_2:
8491                 case CEE_LDC_I4_3:
8492                 case CEE_LDC_I4_4:
8493                 case CEE_LDC_I4_5:
8494                 case CEE_LDC_I4_6:
8495                 case CEE_LDC_I4_7:
8496                 case CEE_LDC_I4_8:
8497                         CHECK_STACK_OVF (1);
8498                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8499                         ++ip;
8500                         *sp++ = ins;
8501                         break;
8502                 case CEE_LDC_I4_S:
8503                         CHECK_OPSIZE (2);
8504                         CHECK_STACK_OVF (1);
8505                         ++ip;
8506                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8507                         ++ip;
8508                         *sp++ = ins;
8509                         break;
8510                 case CEE_LDC_I4:
8511                         CHECK_OPSIZE (5);
8512                         CHECK_STACK_OVF (1);
8513                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8514                         ip += 5;
8515                         *sp++ = ins;
8516                         break;
8517                 case CEE_LDC_I8:
8518                         CHECK_OPSIZE (9);
8519                         CHECK_STACK_OVF (1);
8520                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8521                         ins->type = STACK_I8;
8522                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8523                         ++ip;
8524                         ins->inst_l = (gint64)read64 (ip);
8525                         MONO_ADD_INS (bblock, ins);
8526                         ip += 8;
8527                         *sp++ = ins;
8528                         break;
8529                 case CEE_LDC_R4: {
8530                         float *f;
8531                         gboolean use_aotconst = FALSE;
8532
8533 #ifdef TARGET_POWERPC
8534                         /* FIXME: Clean this up */
8535                         if (cfg->compile_aot)
8536                                 use_aotconst = TRUE;
8537 #endif
8538
8539                         /* FIXME: we should really allocate this only late in the compilation process */
8540                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8541                         CHECK_OPSIZE (5);
8542                         CHECK_STACK_OVF (1);
8543
8544                         if (use_aotconst) {
8545                                 MonoInst *cons;
8546                                 int dreg;
8547
8548                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8549
8550                                 dreg = alloc_freg (cfg);
8551                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8552                                 ins->type = cfg->r4_stack_type;
8553                         } else {
8554                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8555                                 ins->type = cfg->r4_stack_type;
8556                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8557                                 ins->inst_p0 = f;
8558                                 MONO_ADD_INS (bblock, ins);
8559                         }
8560                         ++ip;
8561                         readr4 (ip, f);
8562                         ip += 4;
8563                         *sp++ = ins;                    
8564                         break;
8565                 }
8566                 case CEE_LDC_R8: {
8567                         double *d;
8568                         gboolean use_aotconst = FALSE;
8569
8570 #ifdef TARGET_POWERPC
8571                         /* FIXME: Clean this up */
8572                         if (cfg->compile_aot)
8573                                 use_aotconst = TRUE;
8574 #endif
8575
8576                         /* FIXME: we should really allocate this only late in the compilation process */
8577                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8578                         CHECK_OPSIZE (9);
8579                         CHECK_STACK_OVF (1);
8580
8581                         if (use_aotconst) {
8582                                 MonoInst *cons;
8583                                 int dreg;
8584
8585                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8586
8587                                 dreg = alloc_freg (cfg);
8588                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8589                                 ins->type = STACK_R8;
8590                         } else {
8591                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8592                                 ins->type = STACK_R8;
8593                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8594                                 ins->inst_p0 = d;
8595                                 MONO_ADD_INS (bblock, ins);
8596                         }
8597                         ++ip;
8598                         readr8 (ip, d);
8599                         ip += 8;
8600                         *sp++ = ins;
8601                         break;
8602                 }
8603                 case CEE_DUP: {
8604                         MonoInst *temp, *store;
8605                         CHECK_STACK (1);
8606                         CHECK_STACK_OVF (1);
8607                         sp--;
8608                         ins = *sp;
8609
8610                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8611                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8612
8613                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8614                         *sp++ = ins;
8615
8616                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8617                         *sp++ = ins;
8618
8619                         ++ip;
8620                         inline_costs += 2;
8621                         break;
8622                 }
8623                 case CEE_POP:
8624                         CHECK_STACK (1);
8625                         ip++;
8626                         --sp;
8627
8628 #ifdef TARGET_X86
8629                         if (sp [0]->type == STACK_R8)
8630                                 /* we need to pop the value from the x86 FP stack */
8631                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8632 #endif
8633                         break;
8634                 case CEE_JMP: {
8635                         MonoCallInst *call;
8636
8637                         INLINE_FAILURE ("jmp");
8638                         GSHAREDVT_FAILURE (*ip);
8639
8640                         CHECK_OPSIZE (5);
8641                         if (stack_start != sp)
8642                                 UNVERIFIED;
8643                         token = read32 (ip + 1);
8644                         /* FIXME: check the signature matches */
8645                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8646
8647                         if (!cmethod || mono_loader_get_last_error ())
8648                                 LOAD_ERROR;
8649  
8650                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8651                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8652
8653                         if (mono_security_cas_enabled ())
8654                                 CHECK_CFG_EXCEPTION;
8655
8656                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8657
8658                         if (ARCH_HAVE_OP_TAIL_CALL) {
8659                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8660                                 int i, n;
8661
8662                                 /* Handle tail calls similarly to calls */
8663                                 n = fsig->param_count + fsig->hasthis;
8664
8665                                 DISABLE_AOT (cfg);
8666
8667                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8668                                 call->method = cmethod;
8669                                 call->tail_call = TRUE;
8670                                 call->signature = mono_method_signature (cmethod);
8671                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8672                                 call->inst.inst_p0 = cmethod;
8673                                 for (i = 0; i < n; ++i)
8674                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8675
8676                                 mono_arch_emit_call (cfg, call);
8677                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8678                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8679                         } else {
8680                                 for (i = 0; i < num_args; ++i)
8681                                         /* Prevent arguments from being optimized away */
8682                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8683
8684                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8685                                 ins = (MonoInst*)call;
8686                                 ins->inst_p0 = cmethod;
8687                                 MONO_ADD_INS (bblock, ins);
8688                         }
8689
8690                         ip += 5;
8691                         start_new_bblock = 1;
8692                         break;
8693                 }
8694                 case CEE_CALLI:
8695                 case CEE_CALL:
8696                 case CEE_CALLVIRT: {
8697                         MonoInst *addr = NULL;
8698                         MonoMethodSignature *fsig = NULL;
8699                         int array_rank = 0;
8700                         int virtual = *ip == CEE_CALLVIRT;
8701                         int calli = *ip == CEE_CALLI;
8702                         gboolean pass_imt_from_rgctx = FALSE;
8703                         MonoInst *imt_arg = NULL;
8704                         MonoInst *keep_this_alive = NULL;
8705                         gboolean pass_vtable = FALSE;
8706                         gboolean pass_mrgctx = FALSE;
8707                         MonoInst *vtable_arg = NULL;
8708                         gboolean check_this = FALSE;
8709                         gboolean supported_tail_call = FALSE;
8710                         gboolean tail_call = FALSE;
8711                         gboolean need_seq_point = FALSE;
8712                         guint32 call_opcode = *ip;
8713                         gboolean emit_widen = TRUE;
8714                         gboolean push_res = TRUE;
8715                         gboolean skip_ret = FALSE;
8716                         gboolean delegate_invoke = FALSE;
8717
8718                         CHECK_OPSIZE (5);
8719                         token = read32 (ip + 1);
8720
8721                         ins = NULL;
8722
8723                         if (calli) {
8724                                 //GSHAREDVT_FAILURE (*ip);
8725                                 cmethod = NULL;
8726                                 CHECK_STACK (1);
8727                                 --sp;
8728                                 addr = *sp;
8729                                 fsig = mini_get_signature (method, token, generic_context);
8730                                 n = fsig->param_count + fsig->hasthis;
8731
8732                                 if (method->dynamic && fsig->pinvoke) {
8733                                         MonoInst *args [3];
8734
8735                                         /*
8736                                          * This is a call through a function pointer using a pinvoke
8737                                          * signature. Have to create a wrapper and call that instead.
8738                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8739                                          * instead based on the signature.
8740                                          */
8741                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8742                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8743                                         args [2] = addr;
8744                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8745                                 }
8746                         } else {
8747                                 MonoMethod *cil_method;
8748
8749                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8750                                 cil_method = cmethod;
8751                                 
8752                                 if (constrained_class) {
8753                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8754                                                 if (cfg->verbose_level > 2)
8755                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8756                                                 if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8757                                                            constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8758                                                           cfg->generic_sharing_context)) {
8759                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8760                                                         CHECK_CFG_ERROR;
8761                                                 }
8762                                         } else {
8763                                                 if (cfg->verbose_level > 2)
8764                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8765
8766                                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8767                                                         /* 
8768                                                          * This is needed since get_method_constrained can't find 
8769                                                          * the method in klass representing a type var.
8770                                                          * The type var is guaranteed to be a reference type in this
8771                                                          * case.
8772                                                          */
8773                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_class))
8774                                                                 g_assert (!cmethod->klass->valuetype);
8775                                                 } else {
8776                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8777                                                         CHECK_CFG_ERROR;
8778                                                 }
8779                                         }
8780                                 }
8781                                         
8782                                 if (!cmethod || mono_loader_get_last_error ())
8783                                         LOAD_ERROR;
8784                                 if (!dont_verify && !cfg->skip_visibility) {
8785                                         MonoMethod *target_method = cil_method;
8786                                         if (method->is_inflated) {
8787                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8788                                         }
8789                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8790                                                 !mono_method_can_access_method (method, cil_method))
8791                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8792                                 }
8793
8794                                 if (mono_security_core_clr_enabled ())
8795                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8796
8797                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8798                                         /* MS.NET seems to silently convert this to a callvirt */
8799                                         virtual = 1;
8800
8801                                 {
8802                                         /*
8803                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8804                                          * converts to a callvirt.
8805                                          *
8806                                          * tests/bug-515884.il is an example of this behavior
8807                                          */
8808                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8809                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8810                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8811                                                 virtual = 1;
8812                                 }
8813
8814                                 if (!cmethod->klass->inited)
8815                                         if (!mono_class_init (cmethod->klass))
8816                                                 TYPE_LOAD_ERROR (cmethod->klass);
8817
8818                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8819                                     mini_class_is_system_array (cmethod->klass)) {
8820                                         array_rank = cmethod->klass->rank;
8821                                         fsig = mono_method_signature (cmethod);
8822                                 } else {
8823                                         fsig = mono_method_signature (cmethod);
8824
8825                                         if (!fsig)
8826                                                 LOAD_ERROR;
8827
8828                                         if (fsig->pinvoke) {
8829                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8830                                                         check_for_pending_exc, cfg->compile_aot);
8831                                                 fsig = mono_method_signature (wrapper);
8832                                         } else if (constrained_class) {
8833                                                 fsig = mono_method_signature (cmethod);
8834                                         } else {
8835                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8836                                                 CHECK_CFG_ERROR;
8837                                         }
8838                                 }
8839
8840                                 mono_save_token_info (cfg, image, token, cil_method);
8841
8842                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8843                                         need_seq_point = TRUE;
8844
8845                                 n = fsig->param_count + fsig->hasthis;
8846
8847                                 /* Don't support calls made using type arguments for now */
8848                                 /*
8849                                 if (cfg->gsharedvt) {
8850                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8851                                                 GSHAREDVT_FAILURE (*ip);
8852                                 }
8853                                 */
8854
8855                                 if (mono_security_cas_enabled ()) {
8856                                         if (check_linkdemand (cfg, method, cmethod))
8857                                                 INLINE_FAILURE ("linkdemand");
8858                                         CHECK_CFG_EXCEPTION;
8859                                 }
8860
8861                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8862                                         g_assert_not_reached ();
8863                         }
8864
8865                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8866                                 UNVERIFIED;
8867
8868                         if (!cfg->generic_sharing_context && cmethod)
8869                                 g_assert (!mono_method_check_context_used (cmethod));
8870
8871                         CHECK_STACK (n);
8872
8873                         //g_assert (!virtual || fsig->hasthis);
8874
8875                         sp -= n;
8876
8877                         if (constrained_class) {
8878                                 if (mini_is_gsharedvt_klass (cfg, constrained_class)) {
8879                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8880                                                 /* The 'Own method' case below */
8881                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8882                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8883                                         } else {
8884                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen, &bblock);
8885                                                 CHECK_CFG_EXCEPTION;
8886                                                 g_assert (ins);
8887                                                 goto call_end;
8888                                         }
8889                                 }
8890
8891                                 /*
8892                                  * We have the `constrained.' prefix opcode.
8893                                  */
8894                                 if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8895                                         /*
8896                                          * The type parameter is instantiated as a valuetype,
8897                                          * but that type doesn't override the method we're
8898                                          * calling, so we need to box `this'.
8899                                          */
8900                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8901                                         ins->klass = constrained_class;
8902                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
8903                                         CHECK_CFG_EXCEPTION;
8904                                 } else if (!constrained_class->valuetype) {
8905                                         int dreg = alloc_ireg_ref (cfg);
8906
8907                                         /*
8908                                          * The type parameter is instantiated as a reference
8909                                          * type.  We have a managed pointer on the stack, so
8910                                          * we need to dereference it here.
8911                                          */
8912                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8913                                         ins->type = STACK_OBJ;
8914                                         sp [0] = ins;
8915                                 } else {
8916                                         if (cmethod->klass->valuetype) {
8917                                                 /* Own method */
8918                                         } else {
8919                                                 /* Interface method */
8920                                                 int ioffset, slot;
8921
8922                                                 mono_class_setup_vtable (constrained_class);
8923                                                 CHECK_TYPELOAD (constrained_class);
8924                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8925                                                 if (ioffset == -1)
8926                                                         TYPE_LOAD_ERROR (constrained_class);
8927                                                 slot = mono_method_get_vtable_slot (cmethod);
8928                                                 if (slot == -1)
8929                                                         TYPE_LOAD_ERROR (cmethod->klass);
8930                                                 cmethod = constrained_class->vtable [ioffset + slot];
8931
8932                                                 if (cmethod->klass == mono_defaults.enum_class) {
8933                                                         /* Enum implements some interfaces, so treat this as the first case */
8934                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8935                                                         ins->klass = constrained_class;
8936                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
8937                                                         CHECK_CFG_EXCEPTION;
8938                                                 }
8939                                         }
8940                                         virtual = 0;
8941                                 }
8942                                 constrained_class = NULL;
8943                         }
8944
8945                         if (!calli && check_call_signature (cfg, fsig, sp))
8946                                 UNVERIFIED;
8947
8948 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8949                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8950                                 delegate_invoke = TRUE;
8951 #endif
8952
8953                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8954                                 bblock = cfg->cbb;
8955                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8956                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8957                                         emit_widen = FALSE;
8958                                 }
8959
8960                                 goto call_end;
8961                         }
8962
8963                         /* 
8964                          * If the callee is a shared method, then its static cctor
8965                          * might not get called after the call was patched.
8966                          */
8967                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
8968                                 emit_generic_class_init (cfg, cmethod->klass);
8969                                 CHECK_TYPELOAD (cmethod->klass);
8970                         }
8971
8972                         if (cmethod)
8973                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8974
8975                         if (cfg->generic_sharing_context && cmethod) {
8976                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8977
8978                                 context_used = mini_method_check_context_used (cfg, cmethod);
8979
8980                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8981                                         /* Generic method interface
8982                                            calls are resolved via a
8983                                            helper function and don't
8984                                            need an imt. */
8985                                         if (!cmethod_context || !cmethod_context->method_inst)
8986                                                 pass_imt_from_rgctx = TRUE;
8987                                 }
8988
8989                                 /*
8990                                  * If a shared method calls another
8991                                  * shared method then the caller must
8992                                  * have a generic sharing context
8993                                  * because the magic trampoline
8994                                  * requires it.  FIXME: We shouldn't
8995                                  * have to force the vtable/mrgctx
8996                                  * variable here.  Instead there
8997                                  * should be a flag in the cfg to
8998                                  * request a generic sharing context.
8999                                  */
9000                                 if (context_used &&
9001                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9002                                         mono_get_vtable_var (cfg);
9003                         }
9004
9005                         if (pass_vtable) {
9006                                 if (context_used) {
9007                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9008                                 } else {
9009                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9010
9011                                         CHECK_TYPELOAD (cmethod->klass);
9012                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9013                                 }
9014                         }
9015
9016                         if (pass_mrgctx) {
9017                                 g_assert (!vtable_arg);
9018
9019                                 if (!cfg->compile_aot) {
9020                                         /* 
9021                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9022                                          * for type load errors before.
9023                                          */
9024                                         mono_class_setup_vtable (cmethod->klass);
9025                                         CHECK_TYPELOAD (cmethod->klass);
9026                                 }
9027
9028                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9029
9030                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9031                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9032                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9033                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9034                                         if (virtual)
9035                                                 check_this = TRUE;
9036                                         virtual = 0;
9037                                 }
9038                         }
9039
9040                         if (pass_imt_from_rgctx) {
9041                                 g_assert (!pass_vtable);
9042                                 g_assert (cmethod);
9043
9044                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9045                                         cmethod, MONO_RGCTX_INFO_METHOD);
9046                         }
9047
9048                         if (check_this)
9049                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9050
9051                         /* Calling virtual generic methods */
9052                         if (cmethod && virtual && 
9053                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9054                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9055                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9056                             fsig->generic_param_count && 
9057                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9058                                 MonoInst *this_temp, *this_arg_temp, *store;
9059                                 MonoInst *iargs [4];
9060                                 gboolean use_imt = FALSE;
9061
9062                                 g_assert (fsig->is_inflated);
9063
9064                                 /* Prevent inlining of methods that contain indirect calls */
9065                                 INLINE_FAILURE ("virtual generic call");
9066
9067                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9068                                         GSHAREDVT_FAILURE (*ip);
9069
9070 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9071                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
9072                                         use_imt = TRUE;
9073 #endif
9074
9075                                 if (use_imt) {
9076                                         g_assert (!imt_arg);
9077                                         if (!context_used)
9078                                                 g_assert (cmethod->is_inflated);
9079                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9080                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9081                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9082                                 } else {
9083                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9084                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9085                                         MONO_ADD_INS (bblock, store);
9086
9087                                         /* FIXME: This should be a managed pointer */
9088                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9089
9090                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9091                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9092                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9093                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9094                                         addr = mono_emit_jit_icall (cfg,
9095                                                                                                 mono_helper_compile_generic_method, iargs);
9096
9097                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9098
9099                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9100                                 }
9101
9102                                 goto call_end;
9103                         }
9104
9105                         /*
9106                          * Implement a workaround for the inherent races involved in locking:
9107                          * Monitor.Enter ()
9108                          * try {
9109                          * } finally {
9110                          *    Monitor.Exit ()
9111                          * }
9112                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9113                          * try block, the Exit () won't be executed, see:
9114                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9115                          * To work around this, we extend such try blocks to include the last x bytes
9116                          * of the Monitor.Enter () call.
9117                          */
9118                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9119                                 MonoBasicBlock *tbb;
9120
9121                                 GET_BBLOCK (cfg, tbb, ip + 5);
9122                                 /* 
9123                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9124                                  * from Monitor.Enter like ArgumentNullException.
9125                                  */
9126                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9127                                         /* Mark this bblock as needing to be extended */
9128                                         tbb->extend_try_block = TRUE;
9129                                 }
9130                         }
9131
9132                         /* Conversion to a JIT intrinsic */
9133                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9134                                 bblock = cfg->cbb;
9135                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9136                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9137                                         emit_widen = FALSE;
9138                                 }
9139                                 goto call_end;
9140                         }
9141
9142                         /* Inlining */
9143                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
9144                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9145                             mono_method_check_inlining (cfg, cmethod)) {
9146                                 int costs;
9147                                 gboolean always = FALSE;
9148
9149                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9150                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9151                                         /* Prevent inlining of methods that call wrappers */
9152                                         INLINE_FAILURE ("wrapper call");
9153                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9154                                         always = TRUE;
9155                                 }
9156
9157                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
9158                                 if (costs) {
9159                                         cfg->real_offset += 5;
9160
9161                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9162                                                 /* *sp is already set by inline_method */
9163                                                 sp++;
9164                                                 push_res = FALSE;
9165                                         }
9166
9167                                         inline_costs += costs;
9168
9169                                         goto call_end;
9170                                 }
9171                         }
9172
9173                         /* Tail recursion elimination */
9174                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9175                                 gboolean has_vtargs = FALSE;
9176                                 int i;
9177
9178                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9179                                 INLINE_FAILURE ("tail call");
9180
9181                                 /* keep it simple */
9182                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9183                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9184                                                 has_vtargs = TRUE;
9185                                 }
9186
9187                                 if (!has_vtargs) {
9188                                         for (i = 0; i < n; ++i)
9189                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9190                                         MONO_INST_NEW (cfg, ins, OP_BR);
9191                                         MONO_ADD_INS (bblock, ins);
9192                                         tblock = start_bblock->out_bb [0];
9193                                         link_bblock (cfg, bblock, tblock);
9194                                         ins->inst_target_bb = tblock;
9195                                         start_new_bblock = 1;
9196
9197                                         /* skip the CEE_RET, too */
9198                                         if (ip_in_bb (cfg, bblock, ip + 5))
9199                                                 skip_ret = TRUE;
9200                                         push_res = FALSE;
9201                                         goto call_end;
9202                                 }
9203                         }
9204
9205                         inline_costs += 10 * num_calls++;
9206
9207                         /*
9208                          * Making generic calls out of gsharedvt methods.
9209                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9210                          * patching gshared method addresses into a gsharedvt method.
9211                          */
9212                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9213                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9214                                 MonoRgctxInfoType info_type;
9215
9216                                 if (virtual) {
9217                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9218                                                 //GSHAREDVT_FAILURE (*ip);
9219                                         // disable for possible remoting calls
9220                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9221                                                 GSHAREDVT_FAILURE (*ip);
9222                                         if (fsig->generic_param_count) {
9223                                                 /* virtual generic call */
9224                                                 g_assert (mono_use_imt);
9225                                                 g_assert (!imt_arg);
9226                                                 /* Same as the virtual generic case above */
9227                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9228                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9229                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9230                                                 vtable_arg = NULL;
9231                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9232                                                 /* This can happen when we call a fully instantiated iface method */
9233                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9234                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9235                                                 vtable_arg = NULL;
9236                                         }
9237                                 }
9238
9239                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9240                                         keep_this_alive = sp [0];
9241
9242                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9243                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9244                                 else
9245                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9246                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9247
9248                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9249                                 goto call_end;
9250                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9251                                 /*
9252                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9253                                  */
9254                                 MonoInst *callee = addr;
9255
9256                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9257                                         /* Not tested */
9258                                         GSHAREDVT_FAILURE (*ip);
9259
9260                                 addr = emit_get_rgctx_sig (cfg, context_used,
9261                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9262                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9263                                 goto call_end;
9264                         }
9265
9266                         /* Generic sharing */
9267
9268                         /*
9269                          * Use this if the callee is gsharedvt sharable too, since
9270                          * at runtime we might find an instantiation so the call cannot
9271                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9272                          */
9273                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9274                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9275                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9276                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9277                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9278                                 INLINE_FAILURE ("gshared");
9279
9280                                 g_assert (cfg->generic_sharing_context && cmethod);
9281                                 g_assert (!addr);
9282
9283                                 /*
9284                                  * We are compiling a call to a
9285                                  * generic method from shared code,
9286                                  * which means that we have to look up
9287                                  * the method in the rgctx and do an
9288                                  * indirect call.
9289                                  */
9290                                 if (fsig->hasthis)
9291                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9292
9293                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9294                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9295                                 goto call_end;
9296                         }
9297
9298                         /* Indirect calls */
9299                         if (addr) {
9300                                 if (call_opcode == CEE_CALL)
9301                                         g_assert (context_used);
9302                                 else if (call_opcode == CEE_CALLI)
9303                                         g_assert (!vtable_arg);
9304                                 else
9305                                         /* FIXME: what the hell is this??? */
9306                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
9307                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
9308
9309                                 /* Prevent inlining of methods with indirect calls */
9310                                 INLINE_FAILURE ("indirect call");
9311
9312                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9313                                         int info_type;
9314                                         gpointer info_data;
9315
9316                                         /* 
9317                                          * Instead of emitting an indirect call, emit a direct call
9318                                          * with the contents of the aotconst as the patch info.
9319                                          */
9320                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9321                                                 info_type = addr->inst_c1;
9322                                                 info_data = addr->inst_p0;
9323                                         } else {
9324                                                 info_type = addr->inst_right->inst_c1;
9325                                                 info_data = addr->inst_right->inst_left;
9326                                         }
9327                                         
9328                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9329                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9330                                                 NULLIFY_INS (addr);
9331                                                 goto call_end;
9332                                         }
9333                                 }
9334                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9335                                 goto call_end;
9336                         }
9337                                         
9338                         /* Array methods */
9339                         if (array_rank) {
9340                                 MonoInst *addr;
9341
9342                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9343                                         MonoInst *val = sp [fsig->param_count];
9344
9345                                         if (val->type == STACK_OBJ) {
9346                                                 MonoInst *iargs [2];
9347
9348                                                 iargs [0] = sp [0];
9349                                                 iargs [1] = val;
9350                                                 
9351                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9352                                         }
9353                                         
9354                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9355                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9356                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9357                                                 emit_write_barrier (cfg, addr, val);
9358                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9359                                                 GSHAREDVT_FAILURE (*ip);
9360                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9361                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9362
9363                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9364                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9365                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9366                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9367                                         CHECK_TYPELOAD (cmethod->klass);
9368                                         
9369                                         readonly = FALSE;
9370                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9371                                         ins = addr;
9372                                 } else {
9373                                         g_assert_not_reached ();
9374                                 }
9375
9376                                 emit_widen = FALSE;
9377                                 goto call_end;
9378                         }
9379
9380                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9381                         if (ins)
9382                                 goto call_end;
9383
9384                         /* Tail prefix / tail call optimization */
9385
9386                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9387                         /* FIXME: runtime generic context pointer for jumps? */
9388                         /* FIXME: handle this for generic sharing eventually */
9389                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
9390                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9391                                 supported_tail_call = TRUE;
9392
9393                         if (supported_tail_call) {
9394                                 MonoCallInst *call;
9395
9396                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9397                                 INLINE_FAILURE ("tail call");
9398
9399                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9400
9401                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9402                                         /* Handle tail calls similarly to normal calls */
9403                                         tail_call = TRUE;
9404                                 } else {
9405                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9406
9407                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9408                                         call->tail_call = TRUE;
9409                                         call->method = cmethod;
9410                                         call->signature = mono_method_signature (cmethod);
9411
9412                                         /*
9413                                          * We implement tail calls by storing the actual arguments into the 
9414                                          * argument variables, then emitting a CEE_JMP.
9415                                          */
9416                                         for (i = 0; i < n; ++i) {
9417                                                 /* Prevent argument from being register allocated */
9418                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9419                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9420                                         }
9421                                         ins = (MonoInst*)call;
9422                                         ins->inst_p0 = cmethod;
9423                                         ins->inst_p1 = arg_array [0];
9424                                         MONO_ADD_INS (bblock, ins);
9425                                         link_bblock (cfg, bblock, end_bblock);                  
9426                                         start_new_bblock = 1;
9427
9428                                         // FIXME: Eliminate unreachable epilogs
9429
9430                                         /*
9431                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9432                                          * only reachable from this call.
9433                                          */
9434                                         GET_BBLOCK (cfg, tblock, ip + 5);
9435                                         if (tblock == bblock || tblock->in_count == 0)
9436                                                 skip_ret = TRUE;
9437                                         push_res = FALSE;
9438
9439                                         goto call_end;
9440                                 }
9441                         }
9442
9443                         /* 
9444                          * Synchronized wrappers.
9445                          * Its hard to determine where to replace a method with its synchronized
9446                          * wrapper without causing an infinite recursion. The current solution is
9447                          * to add the synchronized wrapper in the trampolines, and to
9448                          * change the called method to a dummy wrapper, and resolve that wrapper
9449                          * to the real method in mono_jit_compile_method ().
9450                          */
9451                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9452                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9453                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9454                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9455                         }
9456
9457                         /* Common call */
9458                         INLINE_FAILURE ("call");
9459                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9460                                                                                           imt_arg, vtable_arg);
9461
9462                         if (tail_call) {
9463                                 link_bblock (cfg, bblock, end_bblock);                  
9464                                 start_new_bblock = 1;
9465
9466                                 // FIXME: Eliminate unreachable epilogs
9467
9468                                 /*
9469                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9470                                  * only reachable from this call.
9471                                  */
9472                                 GET_BBLOCK (cfg, tblock, ip + 5);
9473                                 if (tblock == bblock || tblock->in_count == 0)
9474                                         skip_ret = TRUE;
9475                                 push_res = FALSE;
9476                         }
9477
9478                         call_end:
9479
9480                         /* End of call, INS should contain the result of the call, if any */
9481
9482                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9483                                 g_assert (ins);
9484                                 if (emit_widen)
9485                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9486                                 else
9487                                         *sp++ = ins;
9488                         }
9489
9490                         if (keep_this_alive) {
9491                                 MonoInst *dummy_use;
9492
9493                                 /* See mono_emit_method_call_full () */
9494                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9495                         }
9496
9497                         CHECK_CFG_EXCEPTION;
9498
9499                         ip += 5;
9500                         if (skip_ret) {
9501                                 g_assert (*ip == CEE_RET);
9502                                 ip += 1;
9503                         }
9504                         ins_flag = 0;
9505                         constrained_class = NULL;
9506                         if (need_seq_point)
9507                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9508                         break;
9509                 }
9510                 case CEE_RET:
9511                         if (cfg->method != method) {
9512                                 /* return from inlined method */
9513                                 /* 
9514                                  * If in_count == 0, that means the ret is unreachable due to
9515                                  * being preceeded by a throw. In that case, inline_method () will
9516                                  * handle setting the return value 
9517                                  * (test case: test_0_inline_throw ()).
9518                                  */
9519                                 if (return_var && cfg->cbb->in_count) {
9520                                         MonoType *ret_type = mono_method_signature (method)->ret;
9521
9522                                         MonoInst *store;
9523                                         CHECK_STACK (1);
9524                                         --sp;
9525
9526                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9527                                                 UNVERIFIED;
9528
9529                                         //g_assert (returnvar != -1);
9530                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9531                                         cfg->ret_var_set = TRUE;
9532                                 } 
9533                         } else {
9534                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9535
9536                                 if (cfg->lmf_var && cfg->cbb->in_count)
9537                                         emit_pop_lmf (cfg);
9538
9539                                 if (cfg->ret) {
9540                                         MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
9541
9542                                         if (seq_points && !sym_seq_points) {
9543                                                 /* 
9544                                                  * Place a seq point here too even through the IL stack is not
9545                                                  * empty, so a step over on
9546                                                  * call <FOO>
9547                                                  * ret
9548                                                  * will work correctly.
9549                                                  */
9550                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9551                                                 MONO_ADD_INS (cfg->cbb, ins);
9552                                         }
9553
9554                                         g_assert (!return_var);
9555                                         CHECK_STACK (1);
9556                                         --sp;
9557
9558                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9559                                                 UNVERIFIED;
9560
9561                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9562                                                 MonoInst *ret_addr;
9563
9564                                                 if (!cfg->vret_addr) {
9565                                                         MonoInst *ins;
9566
9567                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9568                                                 } else {
9569                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9570
9571                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9572                                                         ins->klass = mono_class_from_mono_type (ret_type);
9573                                                 }
9574                                         } else {
9575 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9576                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9577                                                         MonoInst *iargs [1];
9578                                                         MonoInst *conv;
9579
9580                                                         iargs [0] = *sp;
9581                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9582                                                         mono_arch_emit_setret (cfg, method, conv);
9583                                                 } else {
9584                                                         mono_arch_emit_setret (cfg, method, *sp);
9585                                                 }
9586 #else
9587                                                 mono_arch_emit_setret (cfg, method, *sp);
9588 #endif
9589                                         }
9590                                 }
9591                         }
9592                         if (sp != stack_start)
9593                                 UNVERIFIED;
9594                         MONO_INST_NEW (cfg, ins, OP_BR);
9595                         ip++;
9596                         ins->inst_target_bb = end_bblock;
9597                         MONO_ADD_INS (bblock, ins);
9598                         link_bblock (cfg, bblock, end_bblock);
9599                         start_new_bblock = 1;
9600                         break;
9601                 case CEE_BR_S:
9602                         CHECK_OPSIZE (2);
9603                         MONO_INST_NEW (cfg, ins, OP_BR);
9604                         ip++;
9605                         target = ip + 1 + (signed char)(*ip);
9606                         ++ip;
9607                         GET_BBLOCK (cfg, tblock, target);
9608                         link_bblock (cfg, bblock, tblock);
9609                         ins->inst_target_bb = tblock;
9610                         if (sp != stack_start) {
9611                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9612                                 sp = stack_start;
9613                                 CHECK_UNVERIFIABLE (cfg);
9614                         }
9615                         MONO_ADD_INS (bblock, ins);
9616                         start_new_bblock = 1;
9617                         inline_costs += BRANCH_COST;
9618                         break;
9619                 case CEE_BEQ_S:
9620                 case CEE_BGE_S:
9621                 case CEE_BGT_S:
9622                 case CEE_BLE_S:
9623                 case CEE_BLT_S:
9624                 case CEE_BNE_UN_S:
9625                 case CEE_BGE_UN_S:
9626                 case CEE_BGT_UN_S:
9627                 case CEE_BLE_UN_S:
9628                 case CEE_BLT_UN_S:
9629                         CHECK_OPSIZE (2);
9630                         CHECK_STACK (2);
9631                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9632                         ip++;
9633                         target = ip + 1 + *(signed char*)ip;
9634                         ip++;
9635
9636                         ADD_BINCOND (NULL);
9637
9638                         sp = stack_start;
9639                         inline_costs += BRANCH_COST;
9640                         break;
9641                 case CEE_BR:
9642                         CHECK_OPSIZE (5);
9643                         MONO_INST_NEW (cfg, ins, OP_BR);
9644                         ip++;
9645
9646                         target = ip + 4 + (gint32)read32(ip);
9647                         ip += 4;
9648                         GET_BBLOCK (cfg, tblock, target);
9649                         link_bblock (cfg, bblock, tblock);
9650                         ins->inst_target_bb = tblock;
9651                         if (sp != stack_start) {
9652                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9653                                 sp = stack_start;
9654                                 CHECK_UNVERIFIABLE (cfg);
9655                         }
9656
9657                         MONO_ADD_INS (bblock, ins);
9658
9659                         start_new_bblock = 1;
9660                         inline_costs += BRANCH_COST;
9661                         break;
9662                 case CEE_BRFALSE_S:
9663                 case CEE_BRTRUE_S:
9664                 case CEE_BRFALSE:
9665                 case CEE_BRTRUE: {
9666                         MonoInst *cmp;
9667                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9668                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9669                         guint32 opsize = is_short ? 1 : 4;
9670
9671                         CHECK_OPSIZE (opsize);
9672                         CHECK_STACK (1);
9673                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9674                                 UNVERIFIED;
9675                         ip ++;
9676                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9677                         ip += opsize;
9678
9679                         sp--;
9680
9681                         GET_BBLOCK (cfg, tblock, target);
9682                         link_bblock (cfg, bblock, tblock);
9683                         GET_BBLOCK (cfg, tblock, ip);
9684                         link_bblock (cfg, bblock, tblock);
9685
9686                         if (sp != stack_start) {
9687                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9688                                 CHECK_UNVERIFIABLE (cfg);
9689                         }
9690
9691                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9692                         cmp->sreg1 = sp [0]->dreg;
9693                         type_from_op (cfg, cmp, sp [0], NULL);
9694                         CHECK_TYPE (cmp);
9695
9696 #if SIZEOF_REGISTER == 4
9697                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9698                                 /* Convert it to OP_LCOMPARE */
9699                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9700                                 ins->type = STACK_I8;
9701                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9702                                 ins->inst_l = 0;
9703                                 MONO_ADD_INS (bblock, ins);
9704                                 cmp->opcode = OP_LCOMPARE;
9705                                 cmp->sreg2 = ins->dreg;
9706                         }
9707 #endif
9708                         MONO_ADD_INS (bblock, cmp);
9709
9710                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9711                         type_from_op (cfg, ins, sp [0], NULL);
9712                         MONO_ADD_INS (bblock, ins);
9713                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9714                         GET_BBLOCK (cfg, tblock, target);
9715                         ins->inst_true_bb = tblock;
9716                         GET_BBLOCK (cfg, tblock, ip);
9717                         ins->inst_false_bb = tblock;
9718                         start_new_bblock = 2;
9719
9720                         sp = stack_start;
9721                         inline_costs += BRANCH_COST;
9722                         break;
9723                 }
9724                 case CEE_BEQ:
9725                 case CEE_BGE:
9726                 case CEE_BGT:
9727                 case CEE_BLE:
9728                 case CEE_BLT:
9729                 case CEE_BNE_UN:
9730                 case CEE_BGE_UN:
9731                 case CEE_BGT_UN:
9732                 case CEE_BLE_UN:
9733                 case CEE_BLT_UN:
9734                         CHECK_OPSIZE (5);
9735                         CHECK_STACK (2);
9736                         MONO_INST_NEW (cfg, ins, *ip);
9737                         ip++;
9738                         target = ip + 4 + (gint32)read32(ip);
9739                         ip += 4;
9740
9741                         ADD_BINCOND (NULL);
9742
9743                         sp = stack_start;
9744                         inline_costs += BRANCH_COST;
9745                         break;
9746                 case CEE_SWITCH: {
9747                         MonoInst *src1;
9748                         MonoBasicBlock **targets;
9749                         MonoBasicBlock *default_bblock;
9750                         MonoJumpInfoBBTable *table;
9751                         int offset_reg = alloc_preg (cfg);
9752                         int target_reg = alloc_preg (cfg);
9753                         int table_reg = alloc_preg (cfg);
9754                         int sum_reg = alloc_preg (cfg);
9755                         gboolean use_op_switch;
9756
9757                         CHECK_OPSIZE (5);
9758                         CHECK_STACK (1);
9759                         n = read32 (ip + 1);
9760                         --sp;
9761                         src1 = sp [0];
9762                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9763                                 UNVERIFIED;
9764
9765                         ip += 5;
9766                         CHECK_OPSIZE (n * sizeof (guint32));
9767                         target = ip + n * sizeof (guint32);
9768
9769                         GET_BBLOCK (cfg, default_bblock, target);
9770                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9771
9772                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9773                         for (i = 0; i < n; ++i) {
9774                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9775                                 targets [i] = tblock;
9776                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9777                                 ip += 4;
9778                         }
9779
9780                         if (sp != stack_start) {
9781                                 /* 
9782                                  * Link the current bb with the targets as well, so handle_stack_args
9783                                  * will set their in_stack correctly.
9784                                  */
9785                                 link_bblock (cfg, bblock, default_bblock);
9786                                 for (i = 0; i < n; ++i)
9787                                         link_bblock (cfg, bblock, targets [i]);
9788
9789                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9790                                 sp = stack_start;
9791                                 CHECK_UNVERIFIABLE (cfg);
9792                         }
9793
9794                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9795                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9796                         bblock = cfg->cbb;
9797
9798                         for (i = 0; i < n; ++i)
9799                                 link_bblock (cfg, bblock, targets [i]);
9800
9801                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9802                         table->table = targets;
9803                         table->table_size = n;
9804
9805                         use_op_switch = FALSE;
9806 #ifdef TARGET_ARM
9807                         /* ARM implements SWITCH statements differently */
9808                         /* FIXME: Make it use the generic implementation */
9809                         if (!cfg->compile_aot)
9810                                 use_op_switch = TRUE;
9811 #endif
9812
9813                         if (COMPILE_LLVM (cfg))
9814                                 use_op_switch = TRUE;
9815
9816                         cfg->cbb->has_jump_table = 1;
9817
9818                         if (use_op_switch) {
9819                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9820                                 ins->sreg1 = src1->dreg;
9821                                 ins->inst_p0 = table;
9822                                 ins->inst_many_bb = targets;
9823                                 ins->klass = GUINT_TO_POINTER (n);
9824                                 MONO_ADD_INS (cfg->cbb, ins);
9825                         } else {
9826                                 if (sizeof (gpointer) == 8)
9827                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9828                                 else
9829                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9830
9831 #if SIZEOF_REGISTER == 8
9832                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9833                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9834 #endif
9835
9836                                 if (cfg->compile_aot) {
9837                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9838                                 } else {
9839                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9840                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9841                                         ins->inst_p0 = table;
9842                                         ins->dreg = table_reg;
9843                                         MONO_ADD_INS (cfg->cbb, ins);
9844                                 }
9845
9846                                 /* FIXME: Use load_memindex */
9847                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9848                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9849                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9850                         }
9851                         start_new_bblock = 1;
9852                         inline_costs += (BRANCH_COST * 2);
9853                         break;
9854                 }
9855                 case CEE_LDIND_I1:
9856                 case CEE_LDIND_U1:
9857                 case CEE_LDIND_I2:
9858                 case CEE_LDIND_U2:
9859                 case CEE_LDIND_I4:
9860                 case CEE_LDIND_U4:
9861                 case CEE_LDIND_I8:
9862                 case CEE_LDIND_I:
9863                 case CEE_LDIND_R4:
9864                 case CEE_LDIND_R8:
9865                 case CEE_LDIND_REF:
9866                         CHECK_STACK (1);
9867                         --sp;
9868
9869                         switch (*ip) {
9870                         case CEE_LDIND_R4:
9871                         case CEE_LDIND_R8:
9872                                 dreg = alloc_freg (cfg);
9873                                 break;
9874                         case CEE_LDIND_I8:
9875                                 dreg = alloc_lreg (cfg);
9876                                 break;
9877                         case CEE_LDIND_REF:
9878                                 dreg = alloc_ireg_ref (cfg);
9879                                 break;
9880                         default:
9881                                 dreg = alloc_preg (cfg);
9882                         }
9883
9884                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9885                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9886                         if (*ip == CEE_LDIND_R4)
9887                                 ins->type = cfg->r4_stack_type;
9888                         ins->flags |= ins_flag;
9889                         MONO_ADD_INS (bblock, ins);
9890                         *sp++ = ins;
9891                         if (ins_flag & MONO_INST_VOLATILE) {
9892                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9893                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9894                         }
9895                         ins_flag = 0;
9896                         ++ip;
9897                         break;
9898                 case CEE_STIND_REF:
9899                 case CEE_STIND_I1:
9900                 case CEE_STIND_I2:
9901                 case CEE_STIND_I4:
9902                 case CEE_STIND_I8:
9903                 case CEE_STIND_R4:
9904                 case CEE_STIND_R8:
9905                 case CEE_STIND_I:
9906                         CHECK_STACK (2);
9907                         sp -= 2;
9908
9909                         if (ins_flag & MONO_INST_VOLATILE) {
9910                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9911                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9912                         }
9913
9914                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9915                         ins->flags |= ins_flag;
9916                         ins_flag = 0;
9917
9918                         MONO_ADD_INS (bblock, ins);
9919
9920                         if (cfg->gen_write_barriers && *ip == CEE_STIND_REF && method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER && !((sp [1]->opcode == OP_PCONST) && (sp [1]->inst_p0 == 0)))
9921                                 emit_write_barrier (cfg, sp [0], sp [1]);
9922
9923                         inline_costs += 1;
9924                         ++ip;
9925                         break;
9926
9927                 case CEE_MUL:
9928                         CHECK_STACK (2);
9929
9930                         MONO_INST_NEW (cfg, ins, (*ip));
9931                         sp -= 2;
9932                         ins->sreg1 = sp [0]->dreg;
9933                         ins->sreg2 = sp [1]->dreg;
9934                         type_from_op (cfg, ins, sp [0], sp [1]);
9935                         CHECK_TYPE (ins);
9936                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9937
9938                         /* Use the immediate opcodes if possible */
9939                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9940                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9941                                 if (imm_opcode != -1) {
9942                                         ins->opcode = imm_opcode;
9943                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9944                                         ins->sreg2 = -1;
9945
9946                                         NULLIFY_INS (sp [1]);
9947                                 }
9948                         }
9949
9950                         MONO_ADD_INS ((cfg)->cbb, (ins));
9951
9952                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
9953                         ip++;
9954                         break;
9955                 case CEE_ADD:
9956                 case CEE_SUB:
9957                 case CEE_DIV:
9958                 case CEE_DIV_UN:
9959                 case CEE_REM:
9960                 case CEE_REM_UN:
9961                 case CEE_AND:
9962                 case CEE_OR:
9963                 case CEE_XOR:
9964                 case CEE_SHL:
9965                 case CEE_SHR:
9966                 case CEE_SHR_UN:
9967                         CHECK_STACK (2);
9968
9969                         MONO_INST_NEW (cfg, ins, (*ip));
9970                         sp -= 2;
9971                         ins->sreg1 = sp [0]->dreg;
9972                         ins->sreg2 = sp [1]->dreg;
9973                         type_from_op (cfg, ins, sp [0], sp [1]);
9974                         CHECK_TYPE (ins);
9975                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9976                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9977
9978                         /* FIXME: Pass opcode to is_inst_imm */
9979
9980                         /* Use the immediate opcodes if possible */
9981                         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)) {
9982                                 int imm_opcode;
9983
9984                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9985 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9986                                 /* Keep emulated opcodes which are optimized away later */
9987                                 if ((ins->opcode == OP_IREM_UN || ins->opcode == OP_IDIV_UN_IMM) && (cfg->opt & (MONO_OPT_CONSPROP | MONO_OPT_COPYPROP)) && sp [1]->opcode == OP_ICONST && mono_is_power_of_two (sp [1]->inst_c0) >= 0) {
9988                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9989                                 }
9990 #endif
9991                                 if (imm_opcode != -1) {
9992                                         ins->opcode = imm_opcode;
9993                                         if (sp [1]->opcode == OP_I8CONST) {
9994 #if SIZEOF_REGISTER == 8
9995                                                 ins->inst_imm = sp [1]->inst_l;
9996 #else
9997                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9998                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9999 #endif
10000                                         }
10001                                         else
10002                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10003                                         ins->sreg2 = -1;
10004
10005                                         /* Might be followed by an instruction added by add_widen_op */
10006                                         if (sp [1]->next == NULL)
10007                                                 NULLIFY_INS (sp [1]);
10008                                 }
10009                         }
10010                         MONO_ADD_INS ((cfg)->cbb, (ins));
10011
10012                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10013                         ip++;
10014                         break;
10015                 case CEE_NEG:
10016                 case CEE_NOT:
10017                 case CEE_CONV_I1:
10018                 case CEE_CONV_I2:
10019                 case CEE_CONV_I4:
10020                 case CEE_CONV_R4:
10021                 case CEE_CONV_R8:
10022                 case CEE_CONV_U4:
10023                 case CEE_CONV_I8:
10024                 case CEE_CONV_U8:
10025                 case CEE_CONV_OVF_I8:
10026                 case CEE_CONV_OVF_U8:
10027                 case CEE_CONV_R_UN:
10028                         CHECK_STACK (1);
10029
10030                         /* Special case this earlier so we have long constants in the IR */
10031                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10032                                 int data = sp [-1]->inst_c0;
10033                                 sp [-1]->opcode = OP_I8CONST;
10034                                 sp [-1]->type = STACK_I8;
10035 #if SIZEOF_REGISTER == 8
10036                                 if ((*ip) == CEE_CONV_U8)
10037                                         sp [-1]->inst_c0 = (guint32)data;
10038                                 else
10039                                         sp [-1]->inst_c0 = data;
10040 #else
10041                                 sp [-1]->inst_ls_word = data;
10042                                 if ((*ip) == CEE_CONV_U8)
10043                                         sp [-1]->inst_ms_word = 0;
10044                                 else
10045                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10046 #endif
10047                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10048                         }
10049                         else {
10050                                 ADD_UNOP (*ip);
10051                         }
10052                         ip++;
10053                         break;
10054                 case CEE_CONV_OVF_I4:
10055                 case CEE_CONV_OVF_I1:
10056                 case CEE_CONV_OVF_I2:
10057                 case CEE_CONV_OVF_I:
10058                 case CEE_CONV_OVF_U:
10059                         CHECK_STACK (1);
10060
10061                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10062                                 ADD_UNOP (CEE_CONV_OVF_I8);
10063                                 ADD_UNOP (*ip);
10064                         } else {
10065                                 ADD_UNOP (*ip);
10066                         }
10067                         ip++;
10068                         break;
10069                 case CEE_CONV_OVF_U1:
10070                 case CEE_CONV_OVF_U2:
10071                 case CEE_CONV_OVF_U4:
10072                         CHECK_STACK (1);
10073
10074                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10075                                 ADD_UNOP (CEE_CONV_OVF_U8);
10076                                 ADD_UNOP (*ip);
10077                         } else {
10078                                 ADD_UNOP (*ip);
10079                         }
10080                         ip++;
10081                         break;
10082                 case CEE_CONV_OVF_I1_UN:
10083                 case CEE_CONV_OVF_I2_UN:
10084                 case CEE_CONV_OVF_I4_UN:
10085                 case CEE_CONV_OVF_I8_UN:
10086                 case CEE_CONV_OVF_U1_UN:
10087                 case CEE_CONV_OVF_U2_UN:
10088                 case CEE_CONV_OVF_U4_UN:
10089                 case CEE_CONV_OVF_U8_UN:
10090                 case CEE_CONV_OVF_I_UN:
10091                 case CEE_CONV_OVF_U_UN:
10092                 case CEE_CONV_U2:
10093                 case CEE_CONV_U1:
10094                 case CEE_CONV_I:
10095                 case CEE_CONV_U:
10096                         CHECK_STACK (1);
10097                         ADD_UNOP (*ip);
10098                         CHECK_CFG_EXCEPTION;
10099                         ip++;
10100                         break;
10101                 case CEE_ADD_OVF:
10102                 case CEE_ADD_OVF_UN:
10103                 case CEE_MUL_OVF:
10104                 case CEE_MUL_OVF_UN:
10105                 case CEE_SUB_OVF:
10106                 case CEE_SUB_OVF_UN:
10107                         CHECK_STACK (2);
10108                         ADD_BINOP (*ip);
10109                         ip++;
10110                         break;
10111                 case CEE_CPOBJ:
10112                         GSHAREDVT_FAILURE (*ip);
10113                         CHECK_OPSIZE (5);
10114                         CHECK_STACK (2);
10115                         token = read32 (ip + 1);
10116                         klass = mini_get_class (method, token, generic_context);
10117                         CHECK_TYPELOAD (klass);
10118                         sp -= 2;
10119                         if (generic_class_is_reference_type (cfg, klass)) {
10120                                 MonoInst *store, *load;
10121                                 int dreg = alloc_ireg_ref (cfg);
10122
10123                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10124                                 load->flags |= ins_flag;
10125                                 MONO_ADD_INS (cfg->cbb, load);
10126
10127                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10128                                 store->flags |= ins_flag;
10129                                 MONO_ADD_INS (cfg->cbb, store);
10130
10131                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10132                                         emit_write_barrier (cfg, sp [0], sp [1]);
10133                         } else {
10134                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10135                         }
10136                         ins_flag = 0;
10137                         ip += 5;
10138                         break;
10139                 case CEE_LDOBJ: {
10140                         int loc_index = -1;
10141                         int stloc_len = 0;
10142
10143                         CHECK_OPSIZE (5);
10144                         CHECK_STACK (1);
10145                         --sp;
10146                         token = read32 (ip + 1);
10147                         klass = mini_get_class (method, token, generic_context);
10148                         CHECK_TYPELOAD (klass);
10149
10150                         /* Optimize the common ldobj+stloc combination */
10151                         switch (ip [5]) {
10152                         case CEE_STLOC_S:
10153                                 loc_index = ip [6];
10154                                 stloc_len = 2;
10155                                 break;
10156                         case CEE_STLOC_0:
10157                         case CEE_STLOC_1:
10158                         case CEE_STLOC_2:
10159                         case CEE_STLOC_3:
10160                                 loc_index = ip [5] - CEE_STLOC_0;
10161                                 stloc_len = 1;
10162                                 break;
10163                         default:
10164                                 break;
10165                         }
10166
10167                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
10168                                 CHECK_LOCAL (loc_index);
10169
10170                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10171                                 ins->dreg = cfg->locals [loc_index]->dreg;
10172                                 ins->flags |= ins_flag;
10173                                 ip += 5;
10174                                 ip += stloc_len;
10175                                 if (ins_flag & MONO_INST_VOLATILE) {
10176                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10177                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10178                                 }
10179                                 ins_flag = 0;
10180                                 break;
10181                         }
10182
10183                         /* Optimize the ldobj+stobj combination */
10184                         /* The reference case ends up being a load+store anyway */
10185                         /* Skip this if the operation is volatile. */
10186                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10187                                 CHECK_STACK (1);
10188
10189                                 sp --;
10190
10191                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10192
10193                                 ip += 5 + 5;
10194                                 ins_flag = 0;
10195                                 break;
10196                         }
10197
10198                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10199                         ins->flags |= ins_flag;
10200                         *sp++ = ins;
10201
10202                         if (ins_flag & MONO_INST_VOLATILE) {
10203                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10204                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10205                         }
10206
10207                         ip += 5;
10208                         ins_flag = 0;
10209                         inline_costs += 1;
10210                         break;
10211                 }
10212                 case CEE_LDSTR:
10213                         CHECK_STACK_OVF (1);
10214                         CHECK_OPSIZE (5);
10215                         n = read32 (ip + 1);
10216
10217                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10218                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10219                                 ins->type = STACK_OBJ;
10220                                 *sp = ins;
10221                         }
10222                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10223                                 MonoInst *iargs [1];
10224                                 char *str = mono_method_get_wrapper_data (method, n);
10225
10226                                 if (cfg->compile_aot)
10227                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10228                                 else
10229                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10230                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10231                         } else {
10232                                 if (cfg->opt & MONO_OPT_SHARED) {
10233                                         MonoInst *iargs [3];
10234
10235                                         if (cfg->compile_aot) {
10236                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10237                                         }
10238                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10239                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10240                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10241                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10242                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10243                                 } else {
10244                                         if (bblock->out_of_line) {
10245                                                 MonoInst *iargs [2];
10246
10247                                                 if (image == mono_defaults.corlib) {
10248                                                         /* 
10249                                                          * Avoid relocations in AOT and save some space by using a 
10250                                                          * version of helper_ldstr specialized to mscorlib.
10251                                                          */
10252                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10253                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10254                                                 } else {
10255                                                         /* Avoid creating the string object */
10256                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10257                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10258                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10259                                                 }
10260                                         } 
10261                                         else
10262                                         if (cfg->compile_aot) {
10263                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10264                                                 *sp = ins;
10265                                                 MONO_ADD_INS (bblock, ins);
10266                                         } 
10267                                         else {
10268                                                 NEW_PCONST (cfg, ins, NULL);
10269                                                 ins->type = STACK_OBJ;
10270                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10271                                                 if (!ins->inst_p0)
10272                                                         OUT_OF_MEMORY_FAILURE;
10273
10274                                                 *sp = ins;
10275                                                 MONO_ADD_INS (bblock, ins);
10276                                         }
10277                                 }
10278                         }
10279
10280                         sp++;
10281                         ip += 5;
10282                         break;
10283                 case CEE_NEWOBJ: {
10284                         MonoInst *iargs [2];
10285                         MonoMethodSignature *fsig;
10286                         MonoInst this_ins;
10287                         MonoInst *alloc;
10288                         MonoInst *vtable_arg = NULL;
10289
10290                         CHECK_OPSIZE (5);
10291                         token = read32 (ip + 1);
10292                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10293                         if (!cmethod || mono_loader_get_last_error ())
10294                                 LOAD_ERROR;
10295                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10296                         CHECK_CFG_ERROR;
10297
10298                         mono_save_token_info (cfg, image, token, cmethod);
10299
10300                         if (!mono_class_init (cmethod->klass))
10301                                 TYPE_LOAD_ERROR (cmethod->klass);
10302
10303                         context_used = mini_method_check_context_used (cfg, cmethod);
10304
10305                         if (mono_security_cas_enabled ()) {
10306                                 if (check_linkdemand (cfg, method, cmethod))
10307                                         INLINE_FAILURE ("linkdemand");
10308                                 CHECK_CFG_EXCEPTION;
10309                         } else if (mono_security_core_clr_enabled ()) {
10310                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10311                         }
10312
10313                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10314                                 emit_generic_class_init (cfg, cmethod->klass);
10315                                 CHECK_TYPELOAD (cmethod->klass);
10316                         }
10317
10318                         /*
10319                         if (cfg->gsharedvt) {
10320                                 if (mini_is_gsharedvt_variable_signature (sig))
10321                                         GSHAREDVT_FAILURE (*ip);
10322                         }
10323                         */
10324
10325                         n = fsig->param_count;
10326                         CHECK_STACK (n);
10327
10328                         /* 
10329                          * Generate smaller code for the common newobj <exception> instruction in
10330                          * argument checking code.
10331                          */
10332                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10333                                 is_exception_class (cmethod->klass) && n <= 2 &&
10334                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10335                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10336                                 MonoInst *iargs [3];
10337
10338                                 sp -= n;
10339
10340                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10341                                 switch (n) {
10342                                 case 0:
10343                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10344                                         break;
10345                                 case 1:
10346                                         iargs [1] = sp [0];
10347                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10348                                         break;
10349                                 case 2:
10350                                         iargs [1] = sp [0];
10351                                         iargs [2] = sp [1];
10352                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10353                                         break;
10354                                 default:
10355                                         g_assert_not_reached ();
10356                                 }
10357
10358                                 ip += 5;
10359                                 inline_costs += 5;
10360                                 break;
10361                         }
10362
10363                         /* move the args to allow room for 'this' in the first position */
10364                         while (n--) {
10365                                 --sp;
10366                                 sp [1] = sp [0];
10367                         }
10368
10369                         /* check_call_signature () requires sp[0] to be set */
10370                         this_ins.type = STACK_OBJ;
10371                         sp [0] = &this_ins;
10372                         if (check_call_signature (cfg, fsig, sp))
10373                                 UNVERIFIED;
10374
10375                         iargs [0] = NULL;
10376
10377                         if (mini_class_is_system_array (cmethod->klass)) {
10378                                 *sp = emit_get_rgctx_method (cfg, context_used,
10379                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10380
10381                                 /* Avoid varargs in the common case */
10382                                 if (fsig->param_count == 1)
10383                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10384                                 else if (fsig->param_count == 2)
10385                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10386                                 else if (fsig->param_count == 3)
10387                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10388                                 else if (fsig->param_count == 4)
10389                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10390                                 else
10391                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10392                         } else if (cmethod->string_ctor) {
10393                                 g_assert (!context_used);
10394                                 g_assert (!vtable_arg);
10395                                 /* we simply pass a null pointer */
10396                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10397                                 /* now call the string ctor */
10398                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10399                         } else {
10400                                 if (cmethod->klass->valuetype) {
10401                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10402                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10403                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10404
10405                                         alloc = NULL;
10406
10407                                         /* 
10408                                          * The code generated by mini_emit_virtual_call () expects
10409                                          * iargs [0] to be a boxed instance, but luckily the vcall
10410                                          * will be transformed into a normal call there.
10411                                          */
10412                                 } else if (context_used) {
10413                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10414                                         *sp = alloc;
10415                                 } else {
10416                                         MonoVTable *vtable = NULL;
10417
10418                                         if (!cfg->compile_aot)
10419                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10420                                         CHECK_TYPELOAD (cmethod->klass);
10421
10422                                         /*
10423                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10424                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10425                                          * As a workaround, we call class cctors before allocating objects.
10426                                          */
10427                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10428                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10429                                                 if (cfg->verbose_level > 2)
10430                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10431                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10432                                         }
10433
10434                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10435                                         *sp = alloc;
10436                                 }
10437                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10438
10439                                 if (alloc)
10440                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10441
10442                                 /* Now call the actual ctor */
10443                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10444                                 CHECK_CFG_EXCEPTION;
10445                         }
10446
10447                         if (alloc == NULL) {
10448                                 /* Valuetype */
10449                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10450                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10451                                 *sp++= ins;
10452                         } else {
10453                                 *sp++ = alloc;
10454                         }
10455                         
10456                         ip += 5;
10457                         inline_costs += 5;
10458                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10459                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10460                         break;
10461                 }
10462                 case CEE_CASTCLASS:
10463                         CHECK_STACK (1);
10464                         --sp;
10465                         CHECK_OPSIZE (5);
10466                         token = read32 (ip + 1);
10467                         klass = mini_get_class (method, token, generic_context);
10468                         CHECK_TYPELOAD (klass);
10469                         if (sp [0]->type != STACK_OBJ)
10470                                 UNVERIFIED;
10471
10472                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10473                         CHECK_CFG_EXCEPTION;
10474
10475                         *sp ++ = ins;
10476                         ip += 5;
10477                         break;
10478                 case CEE_ISINST: {
10479                         CHECK_STACK (1);
10480                         --sp;
10481                         CHECK_OPSIZE (5);
10482                         token = read32 (ip + 1);
10483                         klass = mini_get_class (method, token, generic_context);
10484                         CHECK_TYPELOAD (klass);
10485                         if (sp [0]->type != STACK_OBJ)
10486                                 UNVERIFIED;
10487  
10488                         context_used = mini_class_check_context_used (cfg, klass);
10489
10490                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10491                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10492                                 MonoInst *args [3];
10493
10494                                 /* obj */
10495                                 args [0] = *sp;
10496
10497                                 /* klass */
10498                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10499
10500                                 /* inline cache*/
10501                                 if (cfg->compile_aot)
10502                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
10503                                 else
10504                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10505
10506                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10507                                 ip += 5;
10508                                 inline_costs += 2;
10509                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10510                                 MonoMethod *mono_isinst;
10511                                 MonoInst *iargs [1];
10512                                 int costs;
10513
10514                                 mono_isinst = mono_marshal_get_isinst (klass); 
10515                                 iargs [0] = sp [0];
10516
10517                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10518                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10519                                 CHECK_CFG_EXCEPTION;
10520                                 g_assert (costs > 0);
10521                                 
10522                                 ip += 5;
10523                                 cfg->real_offset += 5;
10524
10525                                 *sp++= iargs [0];
10526
10527                                 inline_costs += costs;
10528                         }
10529                         else {
10530                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10531                                 CHECK_CFG_EXCEPTION;
10532                                 bblock = cfg->cbb;
10533                                 *sp ++ = ins;
10534                                 ip += 5;
10535                         }
10536                         break;
10537                 }
10538                 case CEE_UNBOX_ANY: {
10539                         MonoInst *res, *addr;
10540
10541                         CHECK_STACK (1);
10542                         --sp;
10543                         CHECK_OPSIZE (5);
10544                         token = read32 (ip + 1);
10545                         klass = mini_get_class (method, token, generic_context);
10546                         CHECK_TYPELOAD (klass);
10547
10548                         mono_save_token_info (cfg, image, token, klass);
10549
10550                         context_used = mini_class_check_context_used (cfg, klass);
10551
10552                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10553                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10554                                 inline_costs += 2;
10555                         } else if (generic_class_is_reference_type (cfg, klass)) {
10556                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10557                                 CHECK_CFG_EXCEPTION;
10558                         } else if (mono_class_is_nullable (klass)) {
10559                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10560                         } else {
10561                                 addr = handle_unbox (cfg, klass, sp, context_used);
10562                                 /* LDOBJ */
10563                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10564                                 res = ins;
10565                                 inline_costs += 2;
10566                         }
10567
10568                         *sp ++ = res;
10569                         ip += 5;
10570                         break;
10571                 }
10572                 case CEE_BOX: {
10573                         MonoInst *val;
10574                         MonoClass *enum_class;
10575                         MonoMethod *has_flag;
10576
10577                         CHECK_STACK (1);
10578                         --sp;
10579                         val = *sp;
10580                         CHECK_OPSIZE (5);
10581                         token = read32 (ip + 1);
10582                         klass = mini_get_class (method, token, generic_context);
10583                         CHECK_TYPELOAD (klass);
10584
10585                         mono_save_token_info (cfg, image, token, klass);
10586
10587                         context_used = mini_class_check_context_used (cfg, klass);
10588
10589                         if (generic_class_is_reference_type (cfg, klass)) {
10590                                 *sp++ = val;
10591                                 ip += 5;
10592                                 break;
10593                         }
10594
10595                         if (klass == mono_defaults.void_class)
10596                                 UNVERIFIED;
10597                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10598                                 UNVERIFIED;
10599                         /* frequent check in generic code: box (struct), brtrue */
10600
10601                         /*
10602                          * Look for:
10603                          *
10604                          *   <push int/long ptr>
10605                          *   <push int/long>
10606                          *   box MyFlags
10607                          *   constrained. MyFlags
10608                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10609                          *
10610                          * If we find this sequence and the operand types on box and constrained
10611                          * are equal, we can emit a specialized instruction sequence instead of
10612                          * the very slow HasFlag () call.
10613                          */
10614                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10615                             /* Cheap checks first. */
10616                             ip + 5 + 6 + 5 < end &&
10617                             ip [5] == CEE_PREFIX1 &&
10618                             ip [6] == CEE_CONSTRAINED_ &&
10619                             ip [11] == CEE_CALLVIRT &&
10620                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10621                             mono_class_is_enum (klass) &&
10622                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10623                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10624                             has_flag->klass == mono_defaults.enum_class &&
10625                             !strcmp (has_flag->name, "HasFlag") &&
10626                             has_flag->signature->hasthis &&
10627                             has_flag->signature->param_count == 1) {
10628                                 CHECK_TYPELOAD (enum_class);
10629
10630                                 if (enum_class == klass) {
10631                                         MonoInst *enum_this, *enum_flag;
10632
10633                                         ip += 5 + 6 + 5;
10634                                         --sp;
10635
10636                                         enum_this = sp [0];
10637                                         enum_flag = sp [1];
10638
10639                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10640                                         break;
10641                                 }
10642                         }
10643
10644                         // FIXME: LLVM can't handle the inconsistent bb linking
10645                         if (!mono_class_is_nullable (klass) &&
10646                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10647                                 (ip [5] == CEE_BRTRUE || 
10648                                  ip [5] == CEE_BRTRUE_S ||
10649                                  ip [5] == CEE_BRFALSE ||
10650                                  ip [5] == CEE_BRFALSE_S)) {
10651                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10652                                 int dreg;
10653                                 MonoBasicBlock *true_bb, *false_bb;
10654
10655                                 ip += 5;
10656
10657                                 if (cfg->verbose_level > 3) {
10658                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10659                                         printf ("<box+brtrue opt>\n");
10660                                 }
10661
10662                                 switch (*ip) {
10663                                 case CEE_BRTRUE_S:
10664                                 case CEE_BRFALSE_S:
10665                                         CHECK_OPSIZE (2);
10666                                         ip++;
10667                                         target = ip + 1 + (signed char)(*ip);
10668                                         ip++;
10669                                         break;
10670                                 case CEE_BRTRUE:
10671                                 case CEE_BRFALSE:
10672                                         CHECK_OPSIZE (5);
10673                                         ip++;
10674                                         target = ip + 4 + (gint)(read32 (ip));
10675                                         ip += 4;
10676                                         break;
10677                                 default:
10678                                         g_assert_not_reached ();
10679                                 }
10680
10681                                 /* 
10682                                  * We need to link both bblocks, since it is needed for handling stack
10683                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10684                                  * Branching to only one of them would lead to inconsistencies, so
10685                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10686                                  */
10687                                 GET_BBLOCK (cfg, true_bb, target);
10688                                 GET_BBLOCK (cfg, false_bb, ip);
10689
10690                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10691                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10692
10693                                 if (sp != stack_start) {
10694                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10695                                         sp = stack_start;
10696                                         CHECK_UNVERIFIABLE (cfg);
10697                                 }
10698
10699                                 if (COMPILE_LLVM (cfg)) {
10700                                         dreg = alloc_ireg (cfg);
10701                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10702                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10703
10704                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10705                                 } else {
10706                                         /* The JIT can't eliminate the iconst+compare */
10707                                         MONO_INST_NEW (cfg, ins, OP_BR);
10708                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10709                                         MONO_ADD_INS (cfg->cbb, ins);
10710                                 }
10711
10712                                 start_new_bblock = 1;
10713                                 break;
10714                         }
10715
10716                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10717
10718                         CHECK_CFG_EXCEPTION;
10719                         ip += 5;
10720                         inline_costs += 1;
10721                         break;
10722                 }
10723                 case CEE_UNBOX: {
10724                         CHECK_STACK (1);
10725                         --sp;
10726                         CHECK_OPSIZE (5);
10727                         token = read32 (ip + 1);
10728                         klass = mini_get_class (method, token, generic_context);
10729                         CHECK_TYPELOAD (klass);
10730
10731                         mono_save_token_info (cfg, image, token, klass);
10732
10733                         context_used = mini_class_check_context_used (cfg, klass);
10734
10735                         if (mono_class_is_nullable (klass)) {
10736                                 MonoInst *val;
10737
10738                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10739                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10740
10741                                 *sp++= ins;
10742                         } else {
10743                                 ins = handle_unbox (cfg, klass, sp, context_used);
10744                                 *sp++ = ins;
10745                         }
10746                         ip += 5;
10747                         inline_costs += 2;
10748                         break;
10749                 }
10750                 case CEE_LDFLD:
10751                 case CEE_LDFLDA:
10752                 case CEE_STFLD:
10753                 case CEE_LDSFLD:
10754                 case CEE_LDSFLDA:
10755                 case CEE_STSFLD: {
10756                         MonoClassField *field;
10757 #ifndef DISABLE_REMOTING
10758                         int costs;
10759 #endif
10760                         guint foffset;
10761                         gboolean is_instance;
10762                         int op;
10763                         gpointer addr = NULL;
10764                         gboolean is_special_static;
10765                         MonoType *ftype;
10766                         MonoInst *store_val = NULL;
10767                         MonoInst *thread_ins;
10768
10769                         op = *ip;
10770                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10771                         if (is_instance) {
10772                                 if (op == CEE_STFLD) {
10773                                         CHECK_STACK (2);
10774                                         sp -= 2;
10775                                         store_val = sp [1];
10776                                 } else {
10777                                         CHECK_STACK (1);
10778                                         --sp;
10779                                 }
10780                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10781                                         UNVERIFIED;
10782                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10783                                         UNVERIFIED;
10784                         } else {
10785                                 if (op == CEE_STSFLD) {
10786                                         CHECK_STACK (1);
10787                                         sp--;
10788                                         store_val = sp [0];
10789                                 }
10790                         }
10791
10792                         CHECK_OPSIZE (5);
10793                         token = read32 (ip + 1);
10794                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10795                                 field = mono_method_get_wrapper_data (method, token);
10796                                 klass = field->parent;
10797                         }
10798                         else {
10799                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10800                                 CHECK_CFG_ERROR;
10801                         }
10802                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10803                                 FIELD_ACCESS_FAILURE (method, field);
10804                         mono_class_init (klass);
10805
10806                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10807                                 UNVERIFIED;
10808
10809                         /* if the class is Critical then transparent code cannot access it's fields */
10810                         if (!is_instance && mono_security_core_clr_enabled ())
10811                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10812
10813                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10814                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10815                         if (mono_security_core_clr_enabled ())
10816                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10817                         */
10818
10819                         /*
10820                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10821                          * the static case.
10822                          */
10823                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10824                                 switch (op) {
10825                                 case CEE_LDFLD:
10826                                         op = CEE_LDSFLD;
10827                                         break;
10828                                 case CEE_STFLD:
10829                                         op = CEE_STSFLD;
10830                                         break;
10831                                 case CEE_LDFLDA:
10832                                         op = CEE_LDSFLDA;
10833                                         break;
10834                                 default:
10835                                         g_assert_not_reached ();
10836                                 }
10837                                 is_instance = FALSE;
10838                         }
10839
10840                         context_used = mini_class_check_context_used (cfg, klass);
10841
10842                         /* INSTANCE CASE */
10843
10844                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10845                         if (op == CEE_STFLD) {
10846                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10847                                         UNVERIFIED;
10848 #ifndef DISABLE_REMOTING
10849                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10850                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10851                                         MonoInst *iargs [5];
10852
10853                                         GSHAREDVT_FAILURE (op);
10854
10855                                         iargs [0] = sp [0];
10856                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10857                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10858                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10859                                                     field->offset);
10860                                         iargs [4] = sp [1];
10861
10862                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10863                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10864                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10865                                                 CHECK_CFG_EXCEPTION;
10866                                                 g_assert (costs > 0);
10867                                                       
10868                                                 cfg->real_offset += 5;
10869
10870                                                 inline_costs += costs;
10871                                         } else {
10872                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10873                                         }
10874                                 } else
10875 #endif
10876                                 {
10877                                         MonoInst *store;
10878
10879                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10880
10881                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10882                                                 MonoInst *offset_ins;
10883
10884                                                 context_used = mini_class_check_context_used (cfg, klass);
10885
10886                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10887                                                 dreg = alloc_ireg_mp (cfg);
10888                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10889                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10890                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10891                                         } else {
10892                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10893                                         }
10894                                         if (sp [0]->opcode != OP_LDADDR)
10895                                                 store->flags |= MONO_INST_FAULT;
10896
10897                                 if (cfg->gen_write_barriers && mini_type_to_stind (cfg, field->type) == CEE_STIND_REF && !(sp [1]->opcode == OP_PCONST && sp [1]->inst_c0 == 0)) {
10898                                         /* insert call to write barrier */
10899                                         MonoInst *ptr;
10900                                         int dreg;
10901
10902                                         dreg = alloc_ireg_mp (cfg);
10903                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10904                                         emit_write_barrier (cfg, ptr, sp [1]);
10905                                 }
10906
10907                                         store->flags |= ins_flag;
10908                                 }
10909                                 ins_flag = 0;
10910                                 ip += 5;
10911                                 break;
10912                         }
10913
10914 #ifndef DISABLE_REMOTING
10915                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10916                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10917                                 MonoInst *iargs [4];
10918
10919                                 GSHAREDVT_FAILURE (op);
10920
10921                                 iargs [0] = sp [0];
10922                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10923                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10924                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10925                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10926                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10927                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10928                                         CHECK_CFG_EXCEPTION;
10929                                         g_assert (costs > 0);
10930                                                       
10931                                         cfg->real_offset += 5;
10932
10933                                         *sp++ = iargs [0];
10934
10935                                         inline_costs += costs;
10936                                 } else {
10937                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10938                                         *sp++ = ins;
10939                                 }
10940                         } else 
10941 #endif
10942                         if (is_instance) {
10943                                 if (sp [0]->type == STACK_VTYPE) {
10944                                         MonoInst *var;
10945
10946                                         /* Have to compute the address of the variable */
10947
10948                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10949                                         if (!var)
10950                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10951                                         else
10952                                                 g_assert (var->klass == klass);
10953                                         
10954                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10955                                         sp [0] = ins;
10956                                 }
10957
10958                                 if (op == CEE_LDFLDA) {
10959                                         if (is_magic_tls_access (field)) {
10960                                                 GSHAREDVT_FAILURE (*ip);
10961                                                 ins = sp [0];
10962                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10963                                         } else {
10964                                                 if (sp [0]->type == STACK_OBJ) {
10965                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10966                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10967                                                 }
10968
10969                                                 dreg = alloc_ireg_mp (cfg);
10970
10971                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10972                                                         MonoInst *offset_ins;
10973
10974                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10975                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10976                                                 } else {
10977                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10978                                                 }
10979                                                 ins->klass = mono_class_from_mono_type (field->type);
10980                                                 ins->type = STACK_MP;
10981                                                 *sp++ = ins;
10982                                         }
10983                                 } else {
10984                                         MonoInst *load;
10985
10986                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10987
10988                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10989                                                 MonoInst *offset_ins;
10990
10991                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10992                                                 dreg = alloc_ireg_mp (cfg);
10993                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10994                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10995                                         } else {
10996                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10997                                         }
10998                                         load->flags |= ins_flag;
10999                                         if (sp [0]->opcode != OP_LDADDR)
11000                                                 load->flags |= MONO_INST_FAULT;
11001                                         *sp++ = load;
11002                                 }
11003                         }
11004
11005                         if (is_instance) {
11006                                 ins_flag = 0;
11007                                 ip += 5;
11008                                 break;
11009                         }
11010
11011                         /* STATIC CASE */
11012
11013                         /*
11014                          * We can only support shared generic static
11015                          * field access on architectures where the
11016                          * trampoline code has been extended to handle
11017                          * the generic class init.
11018                          */
11019 #ifndef MONO_ARCH_VTABLE_REG
11020                         GENERIC_SHARING_FAILURE (op);
11021 #endif
11022
11023                         context_used = mini_class_check_context_used (cfg, klass);
11024
11025                         ftype = mono_field_get_type (field);
11026
11027                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11028                                 UNVERIFIED;
11029
11030                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11031                          * to be called here.
11032                          */
11033                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11034                                 mono_class_vtable (cfg->domain, klass);
11035                                 CHECK_TYPELOAD (klass);
11036                         }
11037                         mono_domain_lock (cfg->domain);
11038                         if (cfg->domain->special_static_fields)
11039                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11040                         mono_domain_unlock (cfg->domain);
11041
11042                         is_special_static = mono_class_field_is_special_static (field);
11043
11044                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11045                                 thread_ins = mono_get_thread_intrinsic (cfg);
11046                         else
11047                                 thread_ins = NULL;
11048
11049                         /* Generate IR to compute the field address */
11050                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11051                                 /*
11052                                  * Fast access to TLS data
11053                                  * Inline version of get_thread_static_data () in
11054                                  * threads.c.
11055                                  */
11056                                 guint32 offset;
11057                                 int idx, static_data_reg, array_reg, dreg;
11058
11059                                 GSHAREDVT_FAILURE (op);
11060
11061                                 // offset &= 0x7fffffff;
11062                                 // idx = (offset >> 24) - 1;
11063                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
11064                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11065                                 static_data_reg = alloc_ireg (cfg);
11066                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11067
11068                                 if (cfg->compile_aot) {
11069                                         int offset_reg, offset2_reg, idx_reg;
11070
11071                                         /* For TLS variables, this will return the TLS offset */
11072                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11073                                         offset_reg = ins->dreg;
11074                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11075                                         idx_reg = alloc_ireg (cfg);
11076                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
11077                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
11078                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11079                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11080                                         array_reg = alloc_ireg (cfg);
11081                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11082                                         offset2_reg = alloc_ireg (cfg);
11083                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
11084                                         dreg = alloc_ireg (cfg);
11085                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11086                                 } else {
11087                                         offset = (gsize)addr & 0x7fffffff;
11088                                         idx = (offset >> 24) - 1;
11089
11090                                         array_reg = alloc_ireg (cfg);
11091                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11092                                         dreg = alloc_ireg (cfg);
11093                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
11094                                 }
11095                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11096                                         (cfg->compile_aot && is_special_static) ||
11097                                         (context_used && is_special_static)) {
11098                                 MonoInst *iargs [2];
11099
11100                                 g_assert (field->parent);
11101                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11102                                 if (context_used) {
11103                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11104                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11105                                 } else {
11106                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11107                                 }
11108                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11109                         } else if (context_used) {
11110                                 MonoInst *static_data;
11111
11112                                 /*
11113                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11114                                         method->klass->name_space, method->klass->name, method->name,
11115                                         depth, field->offset);
11116                                 */
11117
11118                                 if (mono_class_needs_cctor_run (klass, method))
11119                                         emit_generic_class_init (cfg, klass);
11120
11121                                 /*
11122                                  * The pointer we're computing here is
11123                                  *
11124                                  *   super_info.static_data + field->offset
11125                                  */
11126                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11127                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11128
11129                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11130                                         MonoInst *offset_ins;
11131
11132                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11133                                         dreg = alloc_ireg_mp (cfg);
11134                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11135                                 } else if (field->offset == 0) {
11136                                         ins = static_data;
11137                                 } else {
11138                                         int addr_reg = mono_alloc_preg (cfg);
11139                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11140                                 }
11141                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11142                                 MonoInst *iargs [2];
11143
11144                                 g_assert (field->parent);
11145                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11146                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11147                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11148                         } else {
11149                                 MonoVTable *vtable = NULL;
11150
11151                                 if (!cfg->compile_aot)
11152                                         vtable = mono_class_vtable (cfg->domain, klass);
11153                                 CHECK_TYPELOAD (klass);
11154
11155                                 if (!addr) {
11156                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11157                                                 if (!(g_slist_find (class_inits, klass))) {
11158                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
11159                                                         if (cfg->verbose_level > 2)
11160                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11161                                                         class_inits = g_slist_prepend (class_inits, klass);
11162                                                 }
11163                                         } else {
11164                                                 if (cfg->run_cctors) {
11165                                                         MonoException *ex;
11166                                                         /* This makes so that inline cannot trigger */
11167                                                         /* .cctors: too many apps depend on them */
11168                                                         /* running with a specific order... */
11169                                                         g_assert (vtable);
11170                                                         if (! vtable->initialized)
11171                                                                 INLINE_FAILURE ("class init");
11172                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11173                                                         if (ex) {
11174                                                                 set_exception_object (cfg, ex);
11175                                                                 goto exception_exit;
11176                                                         }
11177                                                 }
11178                                         }
11179                                         if (cfg->compile_aot)
11180                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11181                                         else {
11182                                                 g_assert (vtable);
11183                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11184                                                 g_assert (addr);
11185                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11186                                         }
11187                                 } else {
11188                                         MonoInst *iargs [1];
11189                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11190                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11191                                 }
11192                         }
11193
11194                         /* Generate IR to do the actual load/store operation */
11195
11196                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11197                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11198                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11199                         }
11200
11201                         if (op == CEE_LDSFLDA) {
11202                                 ins->klass = mono_class_from_mono_type (ftype);
11203                                 ins->type = STACK_PTR;
11204                                 *sp++ = ins;
11205                         } else if (op == CEE_STSFLD) {
11206                                 MonoInst *store;
11207
11208                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11209                                 store->flags |= ins_flag;
11210                         } else {
11211                                 gboolean is_const = FALSE;
11212                                 MonoVTable *vtable = NULL;
11213                                 gpointer addr = NULL;
11214
11215                                 if (!context_used) {
11216                                         vtable = mono_class_vtable (cfg->domain, klass);
11217                                         CHECK_TYPELOAD (klass);
11218                                 }
11219                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11220                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11221                                         int ro_type = ftype->type;
11222                                         if (!addr)
11223                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11224                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11225                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11226                                         }
11227
11228                                         GSHAREDVT_FAILURE (op);
11229
11230                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11231                                         is_const = TRUE;
11232                                         switch (ro_type) {
11233                                         case MONO_TYPE_BOOLEAN:
11234                                         case MONO_TYPE_U1:
11235                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11236                                                 sp++;
11237                                                 break;
11238                                         case MONO_TYPE_I1:
11239                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11240                                                 sp++;
11241                                                 break;                                          
11242                                         case MONO_TYPE_CHAR:
11243                                         case MONO_TYPE_U2:
11244                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11245                                                 sp++;
11246                                                 break;
11247                                         case MONO_TYPE_I2:
11248                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11249                                                 sp++;
11250                                                 break;
11251                                                 break;
11252                                         case MONO_TYPE_I4:
11253                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11254                                                 sp++;
11255                                                 break;                                          
11256                                         case MONO_TYPE_U4:
11257                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11258                                                 sp++;
11259                                                 break;
11260                                         case MONO_TYPE_I:
11261                                         case MONO_TYPE_U:
11262                                         case MONO_TYPE_PTR:
11263                                         case MONO_TYPE_FNPTR:
11264                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11265                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11266                                                 sp++;
11267                                                 break;
11268                                         case MONO_TYPE_STRING:
11269                                         case MONO_TYPE_OBJECT:
11270                                         case MONO_TYPE_CLASS:
11271                                         case MONO_TYPE_SZARRAY:
11272                                         case MONO_TYPE_ARRAY:
11273                                                 if (!mono_gc_is_moving ()) {
11274                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11275                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11276                                                         sp++;
11277                                                 } else {
11278                                                         is_const = FALSE;
11279                                                 }
11280                                                 break;
11281                                         case MONO_TYPE_I8:
11282                                         case MONO_TYPE_U8:
11283                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11284                                                 sp++;
11285                                                 break;
11286                                         case MONO_TYPE_R4:
11287                                         case MONO_TYPE_R8:
11288                                         case MONO_TYPE_VALUETYPE:
11289                                         default:
11290                                                 is_const = FALSE;
11291                                                 break;
11292                                         }
11293                                 }
11294
11295                                 if (!is_const) {
11296                                         MonoInst *load;
11297
11298                                         CHECK_STACK_OVF (1);
11299
11300                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11301                                         load->flags |= ins_flag;
11302                                         ins_flag = 0;
11303                                         *sp++ = load;
11304                                 }
11305                         }
11306
11307                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11308                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11309                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11310                         }
11311
11312                         ins_flag = 0;
11313                         ip += 5;
11314                         break;
11315                 }
11316                 case CEE_STOBJ:
11317                         CHECK_STACK (2);
11318                         sp -= 2;
11319                         CHECK_OPSIZE (5);
11320                         token = read32 (ip + 1);
11321                         klass = mini_get_class (method, token, generic_context);
11322                         CHECK_TYPELOAD (klass);
11323                         if (ins_flag & MONO_INST_VOLATILE) {
11324                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11325                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11326                         }
11327                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11328                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11329                         ins->flags |= ins_flag;
11330                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11331                                         generic_class_is_reference_type (cfg, klass)) {
11332                                 /* insert call to write barrier */
11333                                 emit_write_barrier (cfg, sp [0], sp [1]);
11334                         }
11335                         ins_flag = 0;
11336                         ip += 5;
11337                         inline_costs += 1;
11338                         break;
11339
11340                         /*
11341                          * Array opcodes
11342                          */
11343                 case CEE_NEWARR: {
11344                         MonoInst *len_ins;
11345                         const char *data_ptr;
11346                         int data_size = 0;
11347                         guint32 field_token;
11348
11349                         CHECK_STACK (1);
11350                         --sp;
11351
11352                         CHECK_OPSIZE (5);
11353                         token = read32 (ip + 1);
11354
11355                         klass = mini_get_class (method, token, generic_context);
11356                         CHECK_TYPELOAD (klass);
11357
11358                         context_used = mini_class_check_context_used (cfg, klass);
11359
11360                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11361                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11362                                 ins->sreg1 = sp [0]->dreg;
11363                                 ins->type = STACK_I4;
11364                                 ins->dreg = alloc_ireg (cfg);
11365                                 MONO_ADD_INS (cfg->cbb, ins);
11366                                 *sp = mono_decompose_opcode (cfg, ins, &bblock);
11367                         }
11368
11369                         if (context_used) {
11370                                 MonoInst *args [3];
11371                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11372                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11373
11374                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11375
11376                                 /* vtable */
11377                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11378                                         array_class, MONO_RGCTX_INFO_VTABLE);
11379                                 /* array len */
11380                                 args [1] = sp [0];
11381
11382                                 if (managed_alloc)
11383                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11384                                 else
11385                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11386                         } else {
11387                                 if (cfg->opt & MONO_OPT_SHARED) {
11388                                         /* Decompose now to avoid problems with references to the domainvar */
11389                                         MonoInst *iargs [3];
11390
11391                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11392                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11393                                         iargs [2] = sp [0];
11394
11395                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11396                                 } else {
11397                                         /* Decompose later since it is needed by abcrem */
11398                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11399                                         mono_class_vtable (cfg->domain, array_type);
11400                                         CHECK_TYPELOAD (array_type);
11401
11402                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11403                                         ins->dreg = alloc_ireg_ref (cfg);
11404                                         ins->sreg1 = sp [0]->dreg;
11405                                         ins->inst_newa_class = klass;
11406                                         ins->type = STACK_OBJ;
11407                                         ins->klass = array_type;
11408                                         MONO_ADD_INS (cfg->cbb, ins);
11409                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11410                                         cfg->cbb->has_array_access = TRUE;
11411
11412                                         /* Needed so mono_emit_load_get_addr () gets called */
11413                                         mono_get_got_var (cfg);
11414                                 }
11415                         }
11416
11417                         len_ins = sp [0];
11418                         ip += 5;
11419                         *sp++ = ins;
11420                         inline_costs += 1;
11421
11422                         /* 
11423                          * we inline/optimize the initialization sequence if possible.
11424                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11425                          * for small sizes open code the memcpy
11426                          * ensure the rva field is big enough
11427                          */
11428                         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))) {
11429                                 MonoMethod *memcpy_method = get_memcpy_method ();
11430                                 MonoInst *iargs [3];
11431                                 int add_reg = alloc_ireg_mp (cfg);
11432
11433                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11434                                 if (cfg->compile_aot) {
11435                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11436                                 } else {
11437                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11438                                 }
11439                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11440                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11441                                 ip += 11;
11442                         }
11443
11444                         break;
11445                 }
11446                 case CEE_LDLEN:
11447                         CHECK_STACK (1);
11448                         --sp;
11449                         if (sp [0]->type != STACK_OBJ)
11450                                 UNVERIFIED;
11451
11452                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11453                         ins->dreg = alloc_preg (cfg);
11454                         ins->sreg1 = sp [0]->dreg;
11455                         ins->type = STACK_I4;
11456                         /* This flag will be inherited by the decomposition */
11457                         ins->flags |= MONO_INST_FAULT;
11458                         MONO_ADD_INS (cfg->cbb, ins);
11459                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11460                         cfg->cbb->has_array_access = TRUE;
11461                         ip ++;
11462                         *sp++ = ins;
11463                         break;
11464                 case CEE_LDELEMA:
11465                         CHECK_STACK (2);
11466                         sp -= 2;
11467                         CHECK_OPSIZE (5);
11468                         if (sp [0]->type != STACK_OBJ)
11469                                 UNVERIFIED;
11470
11471                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11472
11473                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11474                         CHECK_TYPELOAD (klass);
11475                         /* we need to make sure that this array is exactly the type it needs
11476                          * to be for correctness. the wrappers are lax with their usage
11477                          * so we need to ignore them here
11478                          */
11479                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11480                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11481                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11482                                 CHECK_TYPELOAD (array_class);
11483                         }
11484
11485                         readonly = FALSE;
11486                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11487                         *sp++ = ins;
11488                         ip += 5;
11489                         break;
11490                 case CEE_LDELEM:
11491                 case CEE_LDELEM_I1:
11492                 case CEE_LDELEM_U1:
11493                 case CEE_LDELEM_I2:
11494                 case CEE_LDELEM_U2:
11495                 case CEE_LDELEM_I4:
11496                 case CEE_LDELEM_U4:
11497                 case CEE_LDELEM_I8:
11498                 case CEE_LDELEM_I:
11499                 case CEE_LDELEM_R4:
11500                 case CEE_LDELEM_R8:
11501                 case CEE_LDELEM_REF: {
11502                         MonoInst *addr;
11503
11504                         CHECK_STACK (2);
11505                         sp -= 2;
11506
11507                         if (*ip == CEE_LDELEM) {
11508                                 CHECK_OPSIZE (5);
11509                                 token = read32 (ip + 1);
11510                                 klass = mini_get_class (method, token, generic_context);
11511                                 CHECK_TYPELOAD (klass);
11512                                 mono_class_init (klass);
11513                         }
11514                         else
11515                                 klass = array_access_to_klass (*ip);
11516
11517                         if (sp [0]->type != STACK_OBJ)
11518                                 UNVERIFIED;
11519
11520                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11521
11522                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11523                                 // FIXME-VT: OP_ICONST optimization
11524                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11525                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11526                                 ins->opcode = OP_LOADV_MEMBASE;
11527                         } else if (sp [1]->opcode == OP_ICONST) {
11528                                 int array_reg = sp [0]->dreg;
11529                                 int index_reg = sp [1]->dreg;
11530                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11531
11532                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11533                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11534                         } else {
11535                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11536                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11537                         }
11538                         *sp++ = ins;
11539                         if (*ip == CEE_LDELEM)
11540                                 ip += 5;
11541                         else
11542                                 ++ip;
11543                         break;
11544                 }
11545                 case CEE_STELEM_I:
11546                 case CEE_STELEM_I1:
11547                 case CEE_STELEM_I2:
11548                 case CEE_STELEM_I4:
11549                 case CEE_STELEM_I8:
11550                 case CEE_STELEM_R4:
11551                 case CEE_STELEM_R8:
11552                 case CEE_STELEM_REF:
11553                 case CEE_STELEM: {
11554                         CHECK_STACK (3);
11555                         sp -= 3;
11556
11557                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11558
11559                         if (*ip == CEE_STELEM) {
11560                                 CHECK_OPSIZE (5);
11561                                 token = read32 (ip + 1);
11562                                 klass = mini_get_class (method, token, generic_context);
11563                                 CHECK_TYPELOAD (klass);
11564                                 mono_class_init (klass);
11565                         }
11566                         else
11567                                 klass = array_access_to_klass (*ip);
11568
11569                         if (sp [0]->type != STACK_OBJ)
11570                                 UNVERIFIED;
11571
11572                         emit_array_store (cfg, klass, sp, TRUE);
11573
11574                         if (*ip == CEE_STELEM)
11575                                 ip += 5;
11576                         else
11577                                 ++ip;
11578                         inline_costs += 1;
11579                         break;
11580                 }
11581                 case CEE_CKFINITE: {
11582                         CHECK_STACK (1);
11583                         --sp;
11584
11585                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11586                         ins->sreg1 = sp [0]->dreg;
11587                         ins->dreg = alloc_freg (cfg);
11588                         ins->type = STACK_R8;
11589                         MONO_ADD_INS (bblock, ins);
11590
11591                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
11592
11593                         ++ip;
11594                         break;
11595                 }
11596                 case CEE_REFANYVAL: {
11597                         MonoInst *src_var, *src;
11598
11599                         int klass_reg = alloc_preg (cfg);
11600                         int dreg = alloc_preg (cfg);
11601
11602                         GSHAREDVT_FAILURE (*ip);
11603
11604                         CHECK_STACK (1);
11605                         MONO_INST_NEW (cfg, ins, *ip);
11606                         --sp;
11607                         CHECK_OPSIZE (5);
11608                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11609                         CHECK_TYPELOAD (klass);
11610
11611                         context_used = mini_class_check_context_used (cfg, klass);
11612
11613                         // FIXME:
11614                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11615                         if (!src_var)
11616                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11617                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11618                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11619
11620                         if (context_used) {
11621                                 MonoInst *klass_ins;
11622
11623                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11624                                                 klass, MONO_RGCTX_INFO_KLASS);
11625
11626                                 // FIXME:
11627                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11628                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11629                         } else {
11630                                 mini_emit_class_check (cfg, klass_reg, klass);
11631                         }
11632                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11633                         ins->type = STACK_MP;
11634                         *sp++ = ins;
11635                         ip += 5;
11636                         break;
11637                 }
11638                 case CEE_MKREFANY: {
11639                         MonoInst *loc, *addr;
11640
11641                         GSHAREDVT_FAILURE (*ip);
11642
11643                         CHECK_STACK (1);
11644                         MONO_INST_NEW (cfg, ins, *ip);
11645                         --sp;
11646                         CHECK_OPSIZE (5);
11647                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11648                         CHECK_TYPELOAD (klass);
11649
11650                         context_used = mini_class_check_context_used (cfg, klass);
11651
11652                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11653                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11654
11655                         if (context_used) {
11656                                 MonoInst *const_ins;
11657                                 int type_reg = alloc_preg (cfg);
11658
11659                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11660                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11661                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11662                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11663                         } else if (cfg->compile_aot) {
11664                                 int const_reg = alloc_preg (cfg);
11665                                 int type_reg = alloc_preg (cfg);
11666
11667                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11668                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11669                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11670                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11671                         } else {
11672                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11673                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11674                         }
11675                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11676
11677                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11678                         ins->type = STACK_VTYPE;
11679                         ins->klass = mono_defaults.typed_reference_class;
11680                         *sp++ = ins;
11681                         ip += 5;
11682                         break;
11683                 }
11684                 case CEE_LDTOKEN: {
11685                         gpointer handle;
11686                         MonoClass *handle_class;
11687
11688                         CHECK_STACK_OVF (1);
11689
11690                         CHECK_OPSIZE (5);
11691                         n = read32 (ip + 1);
11692
11693                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11694                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11695                                 handle = mono_method_get_wrapper_data (method, n);
11696                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11697                                 if (handle_class == mono_defaults.typehandle_class)
11698                                         handle = &((MonoClass*)handle)->byval_arg;
11699                         }
11700                         else {
11701                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11702                                 CHECK_CFG_ERROR;
11703                         }
11704                         if (!handle)
11705                                 LOAD_ERROR;
11706                         mono_class_init (handle_class);
11707                         if (cfg->generic_sharing_context) {
11708                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11709                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11710                                         /* This case handles ldtoken
11711                                            of an open type, like for
11712                                            typeof(Gen<>). */
11713                                         context_used = 0;
11714                                 } else if (handle_class == mono_defaults.typehandle_class) {
11715                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11716                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11717                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11718                                 else if (handle_class == mono_defaults.methodhandle_class)
11719                                         context_used = mini_method_check_context_used (cfg, handle);
11720                                 else
11721                                         g_assert_not_reached ();
11722                         }
11723
11724                         if ((cfg->opt & MONO_OPT_SHARED) &&
11725                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11726                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11727                                 MonoInst *addr, *vtvar, *iargs [3];
11728                                 int method_context_used;
11729
11730                                 method_context_used = mini_method_check_context_used (cfg, method);
11731
11732                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11733
11734                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11735                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11736                                 if (method_context_used) {
11737                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11738                                                 method, MONO_RGCTX_INFO_METHOD);
11739                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11740                                 } else {
11741                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11742                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11743                                 }
11744                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11745
11746                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11747
11748                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11749                         } else {
11750                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11751                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11752                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11753                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11754                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11755                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11756
11757                                         mono_class_init (tclass);
11758                                         if (context_used) {
11759                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11760                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11761                                         } else if (cfg->compile_aot) {
11762                                                 if (method->wrapper_type) {
11763                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11764                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11765                                                                 /* Special case for static synchronized wrappers */
11766                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11767                                                         } else {
11768                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11769                                                                 /* FIXME: n is not a normal token */
11770                                                                 DISABLE_AOT (cfg);
11771                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11772                                                         }
11773                                                 } else {
11774                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11775                                                 }
11776                                         } else {
11777                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11778                                         }
11779                                         ins->type = STACK_OBJ;
11780                                         ins->klass = cmethod->klass;
11781                                         ip += 5;
11782                                 } else {
11783                                         MonoInst *addr, *vtvar;
11784
11785                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11786
11787                                         if (context_used) {
11788                                                 if (handle_class == mono_defaults.typehandle_class) {
11789                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11790                                                                         mono_class_from_mono_type (handle),
11791                                                                         MONO_RGCTX_INFO_TYPE);
11792                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11793                                                         ins = emit_get_rgctx_method (cfg, context_used,
11794                                                                         handle, MONO_RGCTX_INFO_METHOD);
11795                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11796                                                         ins = emit_get_rgctx_field (cfg, context_used,
11797                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11798                                                 } else {
11799                                                         g_assert_not_reached ();
11800                                                 }
11801                                         } else if (cfg->compile_aot) {
11802                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11803                                         } else {
11804                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11805                                         }
11806                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11807                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11808                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11809                                 }
11810                         }
11811
11812                         *sp++ = ins;
11813                         ip += 5;
11814                         break;
11815                 }
11816                 case CEE_THROW:
11817                         CHECK_STACK (1);
11818                         MONO_INST_NEW (cfg, ins, OP_THROW);
11819                         --sp;
11820                         ins->sreg1 = sp [0]->dreg;
11821                         ip++;
11822                         bblock->out_of_line = TRUE;
11823                         MONO_ADD_INS (bblock, ins);
11824                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11825                         MONO_ADD_INS (bblock, ins);
11826                         sp = stack_start;
11827                         
11828                         link_bblock (cfg, bblock, end_bblock);
11829                         start_new_bblock = 1;
11830                         break;
11831                 case CEE_ENDFINALLY:
11832                         /* mono_save_seq_point_info () depends on this */
11833                         if (sp != stack_start)
11834                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11835                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11836                         MONO_ADD_INS (bblock, ins);
11837                         ip++;
11838                         start_new_bblock = 1;
11839
11840                         /*
11841                          * Control will leave the method so empty the stack, otherwise
11842                          * the next basic block will start with a nonempty stack.
11843                          */
11844                         while (sp != stack_start) {
11845                                 sp--;
11846                         }
11847                         break;
11848                 case CEE_LEAVE:
11849                 case CEE_LEAVE_S: {
11850                         GList *handlers;
11851
11852                         if (*ip == CEE_LEAVE) {
11853                                 CHECK_OPSIZE (5);
11854                                 target = ip + 5 + (gint32)read32(ip + 1);
11855                         } else {
11856                                 CHECK_OPSIZE (2);
11857                                 target = ip + 2 + (signed char)(ip [1]);
11858                         }
11859
11860                         /* empty the stack */
11861                         while (sp != stack_start) {
11862                                 sp--;
11863                         }
11864
11865                         /* 
11866                          * If this leave statement is in a catch block, check for a
11867                          * pending exception, and rethrow it if necessary.
11868                          * We avoid doing this in runtime invoke wrappers, since those are called
11869                          * by native code which excepts the wrapper to catch all exceptions.
11870                          */
11871                         for (i = 0; i < header->num_clauses; ++i) {
11872                                 MonoExceptionClause *clause = &header->clauses [i];
11873
11874                                 /* 
11875                                  * Use <= in the final comparison to handle clauses with multiple
11876                                  * leave statements, like in bug #78024.
11877                                  * The ordering of the exception clauses guarantees that we find the
11878                                  * innermost clause.
11879                                  */
11880                                 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) {
11881                                         MonoInst *exc_ins;
11882                                         MonoBasicBlock *dont_throw;
11883
11884                                         /*
11885                                           MonoInst *load;
11886
11887                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11888                                         */
11889
11890                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11891
11892                                         NEW_BBLOCK (cfg, dont_throw);
11893
11894                                         /*
11895                                          * Currently, we always rethrow the abort exception, despite the 
11896                                          * fact that this is not correct. See thread6.cs for an example. 
11897                                          * But propagating the abort exception is more important than 
11898                                          * getting the sematics right.
11899                                          */
11900                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11901                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11902                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11903
11904                                         MONO_START_BB (cfg, dont_throw);
11905                                         bblock = cfg->cbb;
11906                                 }
11907                         }
11908
11909                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11910                                 GList *tmp;
11911                                 MonoExceptionClause *clause;
11912
11913                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11914                                         clause = tmp->data;
11915                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11916                                         g_assert (tblock);
11917                                         link_bblock (cfg, bblock, tblock);
11918                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11919                                         ins->inst_target_bb = tblock;
11920                                         ins->inst_eh_block = clause;
11921                                         MONO_ADD_INS (bblock, ins);
11922                                         bblock->has_call_handler = 1;
11923                                         if (COMPILE_LLVM (cfg)) {
11924                                                 MonoBasicBlock *target_bb;
11925
11926                                                 /* 
11927                                                  * Link the finally bblock with the target, since it will
11928                                                  * conceptually branch there.
11929                                                  * FIXME: Have to link the bblock containing the endfinally.
11930                                                  */
11931                                                 GET_BBLOCK (cfg, target_bb, target);
11932                                                 link_bblock (cfg, tblock, target_bb);
11933                                         }
11934                                 }
11935                                 g_list_free (handlers);
11936                         } 
11937
11938                         MONO_INST_NEW (cfg, ins, OP_BR);
11939                         MONO_ADD_INS (bblock, ins);
11940                         GET_BBLOCK (cfg, tblock, target);
11941                         link_bblock (cfg, bblock, tblock);
11942                         ins->inst_target_bb = tblock;
11943                         start_new_bblock = 1;
11944
11945                         if (*ip == CEE_LEAVE)
11946                                 ip += 5;
11947                         else
11948                                 ip += 2;
11949
11950                         break;
11951                 }
11952
11953                         /*
11954                          * Mono specific opcodes
11955                          */
11956                 case MONO_CUSTOM_PREFIX: {
11957
11958                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11959
11960                         CHECK_OPSIZE (2);
11961                         switch (ip [1]) {
11962                         case CEE_MONO_ICALL: {
11963                                 gpointer func;
11964                                 MonoJitICallInfo *info;
11965
11966                                 token = read32 (ip + 2);
11967                                 func = mono_method_get_wrapper_data (method, token);
11968                                 info = mono_find_jit_icall_by_addr (func);
11969                                 if (!info)
11970                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11971                                 g_assert (info);
11972
11973                                 CHECK_STACK (info->sig->param_count);
11974                                 sp -= info->sig->param_count;
11975
11976                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11977                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11978                                         *sp++ = ins;
11979
11980                                 ip += 6;
11981                                 inline_costs += 10 * num_calls++;
11982
11983                                 break;
11984                         }
11985                         case CEE_MONO_LDPTR: {
11986                                 gpointer ptr;
11987
11988                                 CHECK_STACK_OVF (1);
11989                                 CHECK_OPSIZE (6);
11990                                 token = read32 (ip + 2);
11991
11992                                 ptr = mono_method_get_wrapper_data (method, token);
11993                                 /* FIXME: Generalize this */
11994                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11995                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11996                                         *sp++ = ins;
11997                                         ip += 6;
11998                                         break;
11999                                 }
12000                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12001                                 *sp++ = ins;
12002                                 ip += 6;
12003                                 inline_costs += 10 * num_calls++;
12004                                 /* Can't embed random pointers into AOT code */
12005                                 DISABLE_AOT (cfg);
12006                                 break;
12007                         }
12008                         case CEE_MONO_JIT_ICALL_ADDR: {
12009                                 MonoJitICallInfo *callinfo;
12010                                 gpointer ptr;
12011
12012                                 CHECK_STACK_OVF (1);
12013                                 CHECK_OPSIZE (6);
12014                                 token = read32 (ip + 2);
12015
12016                                 ptr = mono_method_get_wrapper_data (method, token);
12017                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12018                                 g_assert (callinfo);
12019                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12020                                 *sp++ = ins;
12021                                 ip += 6;
12022                                 inline_costs += 10 * num_calls++;
12023                                 break;
12024                         }
12025                         case CEE_MONO_ICALL_ADDR: {
12026                                 MonoMethod *cmethod;
12027                                 gpointer ptr;
12028
12029                                 CHECK_STACK_OVF (1);
12030                                 CHECK_OPSIZE (6);
12031                                 token = read32 (ip + 2);
12032
12033                                 cmethod = mono_method_get_wrapper_data (method, token);
12034
12035                                 if (cfg->compile_aot) {
12036                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12037                                 } else {
12038                                         ptr = mono_lookup_internal_call (cmethod);
12039                                         g_assert (ptr);
12040                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12041                                 }
12042                                 *sp++ = ins;
12043                                 ip += 6;
12044                                 break;
12045                         }
12046                         case CEE_MONO_VTADDR: {
12047                                 MonoInst *src_var, *src;
12048
12049                                 CHECK_STACK (1);
12050                                 --sp;
12051
12052                                 // FIXME:
12053                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12054                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12055                                 *sp++ = src;
12056                                 ip += 2;
12057                                 break;
12058                         }
12059                         case CEE_MONO_NEWOBJ: {
12060                                 MonoInst *iargs [2];
12061
12062                                 CHECK_STACK_OVF (1);
12063                                 CHECK_OPSIZE (6);
12064                                 token = read32 (ip + 2);
12065                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12066                                 mono_class_init (klass);
12067                                 NEW_DOMAINCONST (cfg, iargs [0]);
12068                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12069                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12070                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12071                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12072                                 ip += 6;
12073                                 inline_costs += 10 * num_calls++;
12074                                 break;
12075                         }
12076                         case CEE_MONO_OBJADDR:
12077                                 CHECK_STACK (1);
12078                                 --sp;
12079                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12080                                 ins->dreg = alloc_ireg_mp (cfg);
12081                                 ins->sreg1 = sp [0]->dreg;
12082                                 ins->type = STACK_MP;
12083                                 MONO_ADD_INS (cfg->cbb, ins);
12084                                 *sp++ = ins;
12085                                 ip += 2;
12086                                 break;
12087                         case CEE_MONO_LDNATIVEOBJ:
12088                                 /*
12089                                  * Similar to LDOBJ, but instead load the unmanaged 
12090                                  * representation of the vtype to the stack.
12091                                  */
12092                                 CHECK_STACK (1);
12093                                 CHECK_OPSIZE (6);
12094                                 --sp;
12095                                 token = read32 (ip + 2);
12096                                 klass = mono_method_get_wrapper_data (method, token);
12097                                 g_assert (klass->valuetype);
12098                                 mono_class_init (klass);
12099
12100                                 {
12101                                         MonoInst *src, *dest, *temp;
12102
12103                                         src = sp [0];
12104                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12105                                         temp->backend.is_pinvoke = 1;
12106                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12107                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12108
12109                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12110                                         dest->type = STACK_VTYPE;
12111                                         dest->klass = klass;
12112
12113                                         *sp ++ = dest;
12114                                         ip += 6;
12115                                 }
12116                                 break;
12117                         case CEE_MONO_RETOBJ: {
12118                                 /*
12119                                  * Same as RET, but return the native representation of a vtype
12120                                  * to the caller.
12121                                  */
12122                                 g_assert (cfg->ret);
12123                                 g_assert (mono_method_signature (method)->pinvoke); 
12124                                 CHECK_STACK (1);
12125                                 --sp;
12126                                 
12127                                 CHECK_OPSIZE (6);
12128                                 token = read32 (ip + 2);    
12129                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12130
12131                                 if (!cfg->vret_addr) {
12132                                         g_assert (cfg->ret_var_is_local);
12133
12134                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12135                                 } else {
12136                                         EMIT_NEW_RETLOADA (cfg, ins);
12137                                 }
12138                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12139                                 
12140                                 if (sp != stack_start)
12141                                         UNVERIFIED;
12142                                 
12143                                 MONO_INST_NEW (cfg, ins, OP_BR);
12144                                 ins->inst_target_bb = end_bblock;
12145                                 MONO_ADD_INS (bblock, ins);
12146                                 link_bblock (cfg, bblock, end_bblock);
12147                                 start_new_bblock = 1;
12148                                 ip += 6;
12149                                 break;
12150                         }
12151                         case CEE_MONO_CISINST:
12152                         case CEE_MONO_CCASTCLASS: {
12153                                 int token;
12154                                 CHECK_STACK (1);
12155                                 --sp;
12156                                 CHECK_OPSIZE (6);
12157                                 token = read32 (ip + 2);
12158                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12159                                 if (ip [1] == CEE_MONO_CISINST)
12160                                         ins = handle_cisinst (cfg, klass, sp [0]);
12161                                 else
12162                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12163                                 bblock = cfg->cbb;
12164                                 *sp++ = ins;
12165                                 ip += 6;
12166                                 break;
12167                         }
12168                         case CEE_MONO_SAVE_LMF:
12169                         case CEE_MONO_RESTORE_LMF:
12170 #ifdef MONO_ARCH_HAVE_LMF_OPS
12171                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12172                                 MONO_ADD_INS (bblock, ins);
12173                                 cfg->need_lmf_area = TRUE;
12174 #endif
12175                                 ip += 2;
12176                                 break;
12177                         case CEE_MONO_CLASSCONST:
12178                                 CHECK_STACK_OVF (1);
12179                                 CHECK_OPSIZE (6);
12180                                 token = read32 (ip + 2);
12181                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12182                                 *sp++ = ins;
12183                                 ip += 6;
12184                                 inline_costs += 10 * num_calls++;
12185                                 break;
12186                         case CEE_MONO_NOT_TAKEN:
12187                                 bblock->out_of_line = TRUE;
12188                                 ip += 2;
12189                                 break;
12190                         case CEE_MONO_TLS: {
12191                                 int key;
12192
12193                                 CHECK_STACK_OVF (1);
12194                                 CHECK_OPSIZE (6);
12195                                 key = (gint32)read32 (ip + 2);
12196                                 g_assert (key < TLS_KEY_NUM);
12197
12198                                 ins = mono_create_tls_get (cfg, key);
12199                                 if (!ins) {
12200                                         if (cfg->compile_aot) {
12201                                                 DISABLE_AOT (cfg);
12202                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12203                                                 ins->dreg = alloc_preg (cfg);
12204                                                 ins->type = STACK_PTR;
12205                                         } else {
12206                                                 g_assert_not_reached ();
12207                                         }
12208                                 }
12209                                 ins->type = STACK_PTR;
12210                                 MONO_ADD_INS (bblock, ins);
12211                                 *sp++ = ins;
12212                                 ip += 6;
12213                                 break;
12214                         }
12215                         case CEE_MONO_DYN_CALL: {
12216                                 MonoCallInst *call;
12217
12218                                 /* It would be easier to call a trampoline, but that would put an
12219                                  * extra frame on the stack, confusing exception handling. So
12220                                  * implement it inline using an opcode for now.
12221                                  */
12222
12223                                 if (!cfg->dyn_call_var) {
12224                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12225                                         /* prevent it from being register allocated */
12226                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12227                                 }
12228
12229                                 /* Has to use a call inst since it local regalloc expects it */
12230                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12231                                 ins = (MonoInst*)call;
12232                                 sp -= 2;
12233                                 ins->sreg1 = sp [0]->dreg;
12234                                 ins->sreg2 = sp [1]->dreg;
12235                                 MONO_ADD_INS (bblock, ins);
12236
12237                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12238
12239                                 ip += 2;
12240                                 inline_costs += 10 * num_calls++;
12241
12242                                 break;
12243                         }
12244                         case CEE_MONO_MEMORY_BARRIER: {
12245                                 CHECK_OPSIZE (6);
12246                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12247                                 ip += 6;
12248                                 break;
12249                         }
12250                         case CEE_MONO_JIT_ATTACH: {
12251                                 MonoInst *args [16], *domain_ins;
12252                                 MonoInst *ad_ins, *jit_tls_ins;
12253                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12254
12255                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12256
12257                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12258                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12259
12260                                 ad_ins = mono_get_domain_intrinsic (cfg);
12261                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12262
12263                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12264                                         NEW_BBLOCK (cfg, next_bb);
12265                                         NEW_BBLOCK (cfg, call_bb);
12266
12267                                         if (cfg->compile_aot) {
12268                                                 /* AOT code is only used in the root domain */
12269                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12270                                         } else {
12271                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12272                                         }
12273                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12274                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12275                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12276
12277                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12278                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12279                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12280
12281                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12282                                         MONO_START_BB (cfg, call_bb);
12283                                 }
12284
12285                                 if (cfg->compile_aot) {
12286                                         /* AOT code is only used in the root domain */
12287                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12288                                 } else {
12289                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12290                                 }
12291                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12292                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12293
12294                                 if (next_bb) {
12295                                         MONO_START_BB (cfg, next_bb);
12296                                         bblock = cfg->cbb;
12297                                 }
12298                                 ip += 2;
12299                                 break;
12300                         }
12301                         case CEE_MONO_JIT_DETACH: {
12302                                 MonoInst *args [16];
12303
12304                                 /* Restore the original domain */
12305                                 dreg = alloc_ireg (cfg);
12306                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12307                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12308                                 ip += 2;
12309                                 break;
12310                         }
12311                         default:
12312                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12313                                 break;
12314                         }
12315                         break;
12316                 }
12317
12318                 case CEE_PREFIX1: {
12319                         CHECK_OPSIZE (2);
12320                         switch (ip [1]) {
12321                         case CEE_ARGLIST: {
12322                                 /* somewhat similar to LDTOKEN */
12323                                 MonoInst *addr, *vtvar;
12324                                 CHECK_STACK_OVF (1);
12325                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12326
12327                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12328                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12329
12330                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12331                                 ins->type = STACK_VTYPE;
12332                                 ins->klass = mono_defaults.argumenthandle_class;
12333                                 *sp++ = ins;
12334                                 ip += 2;
12335                                 break;
12336                         }
12337                         case CEE_CEQ:
12338                         case CEE_CGT:
12339                         case CEE_CGT_UN:
12340                         case CEE_CLT:
12341                         case CEE_CLT_UN: {
12342                                 MonoInst *cmp, *arg1, *arg2;
12343
12344                                 CHECK_STACK (2);
12345                                 sp -= 2;
12346                                 arg1 = sp [0];
12347                                 arg2 = sp [1];
12348
12349                                 /*
12350                                  * The following transforms:
12351                                  *    CEE_CEQ    into OP_CEQ
12352                                  *    CEE_CGT    into OP_CGT
12353                                  *    CEE_CGT_UN into OP_CGT_UN
12354                                  *    CEE_CLT    into OP_CLT
12355                                  *    CEE_CLT_UN into OP_CLT_UN
12356                                  */
12357                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12358
12359                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12360                                 cmp->sreg1 = arg1->dreg;
12361                                 cmp->sreg2 = arg2->dreg;
12362                                 type_from_op (cfg, cmp, arg1, arg2);
12363                                 CHECK_TYPE (cmp);
12364                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12365                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12366                                         cmp->opcode = OP_LCOMPARE;
12367                                 else if (arg1->type == STACK_R4)
12368                                         cmp->opcode = OP_RCOMPARE;
12369                                 else if (arg1->type == STACK_R8)
12370                                         cmp->opcode = OP_FCOMPARE;
12371                                 else
12372                                         cmp->opcode = OP_ICOMPARE;
12373                                 MONO_ADD_INS (bblock, cmp);
12374                                 ins->type = STACK_I4;
12375                                 ins->dreg = alloc_dreg (cfg, ins->type);
12376                                 type_from_op (cfg, ins, arg1, arg2);
12377
12378                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12379                                         /*
12380                                          * The backends expect the fceq opcodes to do the
12381                                          * comparison too.
12382                                          */
12383                                         ins->sreg1 = cmp->sreg1;
12384                                         ins->sreg2 = cmp->sreg2;
12385                                         NULLIFY_INS (cmp);
12386                                 }
12387                                 MONO_ADD_INS (bblock, ins);
12388                                 *sp++ = ins;
12389                                 ip += 2;
12390                                 break;
12391                         }
12392                         case CEE_LDFTN: {
12393                                 MonoInst *argconst;
12394                                 MonoMethod *cil_method;
12395
12396                                 CHECK_STACK_OVF (1);
12397                                 CHECK_OPSIZE (6);
12398                                 n = read32 (ip + 2);
12399                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12400                                 if (!cmethod || mono_loader_get_last_error ())
12401                                         LOAD_ERROR;
12402                                 mono_class_init (cmethod->klass);
12403
12404                                 mono_save_token_info (cfg, image, n, cmethod);
12405
12406                                 context_used = mini_method_check_context_used (cfg, cmethod);
12407
12408                                 cil_method = cmethod;
12409                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12410                                         METHOD_ACCESS_FAILURE (method, cil_method);
12411
12412                                 if (mono_security_cas_enabled ()) {
12413                                         if (check_linkdemand (cfg, method, cmethod))
12414                                                 INLINE_FAILURE ("linkdemand");
12415                                         CHECK_CFG_EXCEPTION;
12416                                 } else if (mono_security_core_clr_enabled ()) {
12417                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12418                                 }
12419
12420                                 /* 
12421                                  * Optimize the common case of ldftn+delegate creation
12422                                  */
12423                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12424                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12425                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12426                                                 MonoInst *target_ins, *handle_ins;
12427                                                 MonoMethod *invoke;
12428                                                 int invoke_context_used;
12429
12430                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12431                                                 if (!invoke || !mono_method_signature (invoke))
12432                                                         LOAD_ERROR;
12433
12434                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12435
12436                                                 target_ins = sp [-1];
12437
12438                                                 if (mono_security_core_clr_enabled ())
12439                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12440
12441                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12442                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12443                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12444                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12445                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12446                                                         }
12447                                                 }
12448
12449 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12450                                                 /* FIXME: SGEN support */
12451                                                 if (invoke_context_used == 0) {
12452                                                         ip += 6;
12453                                                         if (cfg->verbose_level > 3)
12454                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12455                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12456                                                                 sp --;
12457                                                                 *sp = handle_ins;
12458                                                                 CHECK_CFG_EXCEPTION;
12459                                                                 ip += 5;
12460                                                                 sp ++;
12461                                                                 break;
12462                                                         }
12463                                                         ip -= 6;
12464                                                 }
12465 #endif
12466                                         }
12467                                 }
12468
12469                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12470                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12471                                 *sp++ = ins;
12472                                 
12473                                 ip += 6;
12474                                 inline_costs += 10 * num_calls++;
12475                                 break;
12476                         }
12477                         case CEE_LDVIRTFTN: {
12478                                 MonoInst *args [2];
12479
12480                                 CHECK_STACK (1);
12481                                 CHECK_OPSIZE (6);
12482                                 n = read32 (ip + 2);
12483                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12484                                 if (!cmethod || mono_loader_get_last_error ())
12485                                         LOAD_ERROR;
12486                                 mono_class_init (cmethod->klass);
12487  
12488                                 context_used = mini_method_check_context_used (cfg, cmethod);
12489
12490                                 if (mono_security_cas_enabled ()) {
12491                                         if (check_linkdemand (cfg, method, cmethod))
12492                                                 INLINE_FAILURE ("linkdemand");
12493                                         CHECK_CFG_EXCEPTION;
12494                                 } else if (mono_security_core_clr_enabled ()) {
12495                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12496                                 }
12497
12498                                 /*
12499                                  * Optimize the common case of ldvirtftn+delegate creation
12500                                  */
12501                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12502                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12503                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12504                                                 MonoInst *target_ins, *handle_ins;
12505                                                 MonoMethod *invoke;
12506                                                 int invoke_context_used;
12507
12508                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12509                                                 if (!invoke || !mono_method_signature (invoke))
12510                                                         LOAD_ERROR;
12511
12512                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12513
12514                                                 target_ins = sp [-1];
12515
12516                                                 if (mono_security_core_clr_enabled ())
12517                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12518
12519 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12520                                                 /* FIXME: SGEN support */
12521                                                 if (invoke_context_used == 0) {
12522                                                         ip += 6;
12523                                                         if (cfg->verbose_level > 3)
12524                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12525                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12526                                                                 sp -= 2;
12527                                                                 *sp = handle_ins;
12528                                                                 CHECK_CFG_EXCEPTION;
12529                                                                 ip += 5;
12530                                                                 sp ++;
12531                                                                 break;
12532                                                         }
12533                                                         ip -= 6;
12534                                                 }
12535 #endif
12536                                         }
12537                                 }
12538
12539                                 --sp;
12540                                 args [0] = *sp;
12541
12542                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12543                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12544
12545                                 if (context_used)
12546                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12547                                 else
12548                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12549
12550                                 ip += 6;
12551                                 inline_costs += 10 * num_calls++;
12552                                 break;
12553                         }
12554                         case CEE_LDARG:
12555                                 CHECK_STACK_OVF (1);
12556                                 CHECK_OPSIZE (4);
12557                                 n = read16 (ip + 2);
12558                                 CHECK_ARG (n);
12559                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12560                                 *sp++ = ins;
12561                                 ip += 4;
12562                                 break;
12563                         case CEE_LDARGA:
12564                                 CHECK_STACK_OVF (1);
12565                                 CHECK_OPSIZE (4);
12566                                 n = read16 (ip + 2);
12567                                 CHECK_ARG (n);
12568                                 NEW_ARGLOADA (cfg, ins, n);
12569                                 MONO_ADD_INS (cfg->cbb, ins);
12570                                 *sp++ = ins;
12571                                 ip += 4;
12572                                 break;
12573                         case CEE_STARG:
12574                                 CHECK_STACK (1);
12575                                 --sp;
12576                                 CHECK_OPSIZE (4);
12577                                 n = read16 (ip + 2);
12578                                 CHECK_ARG (n);
12579                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12580                                         UNVERIFIED;
12581                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12582                                 ip += 4;
12583                                 break;
12584                         case CEE_LDLOC:
12585                                 CHECK_STACK_OVF (1);
12586                                 CHECK_OPSIZE (4);
12587                                 n = read16 (ip + 2);
12588                                 CHECK_LOCAL (n);
12589                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12590                                 *sp++ = ins;
12591                                 ip += 4;
12592                                 break;
12593                         case CEE_LDLOCA: {
12594                                 unsigned char *tmp_ip;
12595                                 CHECK_STACK_OVF (1);
12596                                 CHECK_OPSIZE (4);
12597                                 n = read16 (ip + 2);
12598                                 CHECK_LOCAL (n);
12599
12600                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12601                                         ip = tmp_ip;
12602                                         inline_costs += 1;
12603                                         break;
12604                                 }                       
12605                                 
12606                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12607                                 *sp++ = ins;
12608                                 ip += 4;
12609                                 break;
12610                         }
12611                         case CEE_STLOC:
12612                                 CHECK_STACK (1);
12613                                 --sp;
12614                                 CHECK_OPSIZE (4);
12615                                 n = read16 (ip + 2);
12616                                 CHECK_LOCAL (n);
12617                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12618                                         UNVERIFIED;
12619                                 emit_stloc_ir (cfg, sp, header, n);
12620                                 ip += 4;
12621                                 inline_costs += 1;
12622                                 break;
12623                         case CEE_LOCALLOC:
12624                                 CHECK_STACK (1);
12625                                 --sp;
12626                                 if (sp != stack_start) 
12627                                         UNVERIFIED;
12628                                 if (cfg->method != method) 
12629                                         /* 
12630                                          * Inlining this into a loop in a parent could lead to 
12631                                          * stack overflows which is different behavior than the
12632                                          * non-inlined case, thus disable inlining in this case.
12633                                          */
12634                                         INLINE_FAILURE("localloc");
12635
12636                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12637                                 ins->dreg = alloc_preg (cfg);
12638                                 ins->sreg1 = sp [0]->dreg;
12639                                 ins->type = STACK_PTR;
12640                                 MONO_ADD_INS (cfg->cbb, ins);
12641
12642                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12643                                 if (init_locals)
12644                                         ins->flags |= MONO_INST_INIT;
12645
12646                                 *sp++ = ins;
12647                                 ip += 2;
12648                                 break;
12649                         case CEE_ENDFILTER: {
12650                                 MonoExceptionClause *clause, *nearest;
12651                                 int cc;
12652
12653                                 CHECK_STACK (1);
12654                                 --sp;
12655                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12656                                         UNVERIFIED;
12657                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12658                                 ins->sreg1 = (*sp)->dreg;
12659                                 MONO_ADD_INS (bblock, ins);
12660                                 start_new_bblock = 1;
12661                                 ip += 2;
12662
12663                                 nearest = NULL;
12664                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12665                                         clause = &header->clauses [cc];
12666                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12667                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12668                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12669                                                 nearest = clause;
12670                                 }
12671                                 g_assert (nearest);
12672                                 if ((ip - header->code) != nearest->handler_offset)
12673                                         UNVERIFIED;
12674
12675                                 break;
12676                         }
12677                         case CEE_UNALIGNED_:
12678                                 ins_flag |= MONO_INST_UNALIGNED;
12679                                 /* FIXME: record alignment? we can assume 1 for now */
12680                                 CHECK_OPSIZE (3);
12681                                 ip += 3;
12682                                 break;
12683                         case CEE_VOLATILE_:
12684                                 ins_flag |= MONO_INST_VOLATILE;
12685                                 ip += 2;
12686                                 break;
12687                         case CEE_TAIL_:
12688                                 ins_flag   |= MONO_INST_TAILCALL;
12689                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12690                                 /* Can't inline tail calls at this time */
12691                                 inline_costs += 100000;
12692                                 ip += 2;
12693                                 break;
12694                         case CEE_INITOBJ:
12695                                 CHECK_STACK (1);
12696                                 --sp;
12697                                 CHECK_OPSIZE (6);
12698                                 token = read32 (ip + 2);
12699                                 klass = mini_get_class (method, token, generic_context);
12700                                 CHECK_TYPELOAD (klass);
12701                                 if (generic_class_is_reference_type (cfg, klass))
12702                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12703                                 else
12704                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12705                                 ip += 6;
12706                                 inline_costs += 1;
12707                                 break;
12708                         case CEE_CONSTRAINED_:
12709                                 CHECK_OPSIZE (6);
12710                                 token = read32 (ip + 2);
12711                                 constrained_class = mini_get_class (method, token, generic_context);
12712                                 CHECK_TYPELOAD (constrained_class);
12713                                 ip += 6;
12714                                 break;
12715                         case CEE_CPBLK:
12716                         case CEE_INITBLK: {
12717                                 MonoInst *iargs [3];
12718                                 CHECK_STACK (3);
12719                                 sp -= 3;
12720
12721                                 /* Skip optimized paths for volatile operations. */
12722                                 if ((ip [1] == CEE_CPBLK) && !(ins_flag & MONO_INST_VOLATILE) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
12723                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12724                                 } else if ((ip [1] == CEE_INITBLK) && !(ins_flag & MONO_INST_VOLATILE) && (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)) {
12725                                         /* emit_memset only works when val == 0 */
12726                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12727                                 } else {
12728                                         MonoInst *call;
12729                                         iargs [0] = sp [0];
12730                                         iargs [1] = sp [1];
12731                                         iargs [2] = sp [2];
12732                                         if (ip [1] == CEE_CPBLK) {
12733                                                 /*
12734                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12735                                                  * and release barriers for cpblk. It is technically both a load and
12736                                                  * store operation, so it seems like that's the sensible thing to do.
12737                                                  *
12738                                                  * FIXME: We emit full barriers on both sides of the operation for
12739                                                  * simplicity. We should have a separate atomic memcpy method instead.
12740                                                  */
12741                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12742
12743                                                 if (ins_flag & MONO_INST_VOLATILE)
12744                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12745
12746                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12747                                                 call->flags |= ins_flag;
12748
12749                                                 if (ins_flag & MONO_INST_VOLATILE)
12750                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12751                                         } else {
12752                                                 MonoMethod *memset_method = get_memset_method ();
12753                                                 if (ins_flag & MONO_INST_VOLATILE) {
12754                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12755                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12756                                                 }
12757                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12758                                                 call->flags |= ins_flag;
12759                                         }
12760                                 }
12761                                 ip += 2;
12762                                 ins_flag = 0;
12763                                 inline_costs += 1;
12764                                 break;
12765                         }
12766                         case CEE_NO_:
12767                                 CHECK_OPSIZE (3);
12768                                 if (ip [2] & 0x1)
12769                                         ins_flag |= MONO_INST_NOTYPECHECK;
12770                                 if (ip [2] & 0x2)
12771                                         ins_flag |= MONO_INST_NORANGECHECK;
12772                                 /* we ignore the no-nullcheck for now since we
12773                                  * really do it explicitly only when doing callvirt->call
12774                                  */
12775                                 ip += 3;
12776                                 break;
12777                         case CEE_RETHROW: {
12778                                 MonoInst *load;
12779                                 int handler_offset = -1;
12780
12781                                 for (i = 0; i < header->num_clauses; ++i) {
12782                                         MonoExceptionClause *clause = &header->clauses [i];
12783                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12784                                                 handler_offset = clause->handler_offset;
12785                                                 break;
12786                                         }
12787                                 }
12788
12789                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12790
12791                                 if (handler_offset == -1)
12792                                         UNVERIFIED;
12793
12794                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12795                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12796                                 ins->sreg1 = load->dreg;
12797                                 MONO_ADD_INS (bblock, ins);
12798
12799                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12800                                 MONO_ADD_INS (bblock, ins);
12801
12802                                 sp = stack_start;
12803                                 link_bblock (cfg, bblock, end_bblock);
12804                                 start_new_bblock = 1;
12805                                 ip += 2;
12806                                 break;
12807                         }
12808                         case CEE_SIZEOF: {
12809                                 guint32 val;
12810                                 int ialign;
12811
12812                                 CHECK_STACK_OVF (1);
12813                                 CHECK_OPSIZE (6);
12814                                 token = read32 (ip + 2);
12815                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12816                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12817                                         CHECK_CFG_ERROR;
12818
12819                                         val = mono_type_size (type, &ialign);
12820                                 } else {
12821                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12822                                         CHECK_TYPELOAD (klass);
12823
12824                                         val = mono_type_size (&klass->byval_arg, &ialign);
12825
12826                                         if (mini_is_gsharedvt_klass (cfg, klass))
12827                                                 GSHAREDVT_FAILURE (*ip);
12828                                 }
12829                                 EMIT_NEW_ICONST (cfg, ins, val);
12830                                 *sp++= ins;
12831                                 ip += 6;
12832                                 break;
12833                         }
12834                         case CEE_REFANYTYPE: {
12835                                 MonoInst *src_var, *src;
12836
12837                                 GSHAREDVT_FAILURE (*ip);
12838
12839                                 CHECK_STACK (1);
12840                                 --sp;
12841
12842                                 // FIXME:
12843                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12844                                 if (!src_var)
12845                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12846                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12847                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12848                                 *sp++ = ins;
12849                                 ip += 2;
12850                                 break;
12851                         }
12852                         case CEE_READONLY_:
12853                                 readonly = TRUE;
12854                                 ip += 2;
12855                                 break;
12856
12857                         case CEE_UNUSED56:
12858                         case CEE_UNUSED57:
12859                         case CEE_UNUSED70:
12860                         case CEE_UNUSED:
12861                         case CEE_UNUSED99:
12862                                 UNVERIFIED;
12863                                 
12864                         default:
12865                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12866                                 UNVERIFIED;
12867                         }
12868                         break;
12869                 }
12870                 case CEE_UNUSED58:
12871                 case CEE_UNUSED1:
12872                         UNVERIFIED;
12873
12874                 default:
12875                         g_warning ("opcode 0x%02x not handled", *ip);
12876                         UNVERIFIED;
12877                 }
12878         }
12879         if (start_new_bblock != 1)
12880                 UNVERIFIED;
12881
12882         bblock->cil_length = ip - bblock->cil_code;
12883         if (bblock->next_bb) {
12884                 /* This could already be set because of inlining, #693905 */
12885                 MonoBasicBlock *bb = bblock;
12886
12887                 while (bb->next_bb)
12888                         bb = bb->next_bb;
12889                 bb->next_bb = end_bblock;
12890         } else {
12891                 bblock->next_bb = end_bblock;
12892         }
12893
12894         if (cfg->method == method && cfg->domainvar) {
12895                 MonoInst *store;
12896                 MonoInst *get_domain;
12897
12898                 cfg->cbb = init_localsbb;
12899
12900                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12901                         MONO_ADD_INS (cfg->cbb, get_domain);
12902                 } else {
12903                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12904                 }
12905                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12906                 MONO_ADD_INS (cfg->cbb, store);
12907         }
12908
12909 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12910         if (cfg->compile_aot)
12911                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12912                 mono_get_got_var (cfg);
12913 #endif
12914
12915         if (cfg->method == method && cfg->got_var)
12916                 mono_emit_load_got_addr (cfg);
12917
12918         if (init_localsbb) {
12919                 cfg->cbb = init_localsbb;
12920                 cfg->ip = NULL;
12921                 for (i = 0; i < header->num_locals; ++i) {
12922                         emit_init_local (cfg, i, header->locals [i], init_locals);
12923                 }
12924         }
12925
12926         if (cfg->init_ref_vars && cfg->method == method) {
12927                 /* Emit initialization for ref vars */
12928                 // FIXME: Avoid duplication initialization for IL locals.
12929                 for (i = 0; i < cfg->num_varinfo; ++i) {
12930                         MonoInst *ins = cfg->varinfo [i];
12931
12932                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12933                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12934                 }
12935         }
12936
12937         if (cfg->lmf_var && cfg->method == method) {
12938                 cfg->cbb = init_localsbb;
12939                 emit_push_lmf (cfg);
12940         }
12941
12942         cfg->cbb = init_localsbb;
12943         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12944
12945         if (seq_points) {
12946                 MonoBasicBlock *bb;
12947
12948                 /*
12949                  * Make seq points at backward branch targets interruptable.
12950                  */
12951                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12952                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12953                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12954         }
12955
12956         /* Add a sequence point for method entry/exit events */
12957         if (cfg->gen_seq_points_debug_data) {
12958                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12959                 MONO_ADD_INS (init_localsbb, ins);
12960                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12961                 MONO_ADD_INS (cfg->bb_exit, ins);
12962         }
12963
12964         /*
12965          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12966          * the code they refer to was dead (#11880).
12967          */
12968         if (sym_seq_points) {
12969                 for (i = 0; i < header->code_size; ++i) {
12970                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12971                                 MonoInst *ins;
12972
12973                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12974                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12975                         }
12976                 }
12977         }
12978
12979         cfg->ip = NULL;
12980
12981         if (cfg->method == method) {
12982                 MonoBasicBlock *bb;
12983                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12984                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12985                         if (cfg->spvars)
12986                                 mono_create_spvar_for_region (cfg, bb->region);
12987                         if (cfg->verbose_level > 2)
12988                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12989                 }
12990         }
12991
12992         if (inline_costs < 0) {
12993                 char *mname;
12994
12995                 /* Method is too large */
12996                 mname = mono_method_full_name (method, TRUE);
12997                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12998                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12999                 g_free (mname);
13000         }
13001
13002         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13003                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13004
13005         goto cleanup;
13006
13007 mono_error_exit:
13008         g_assert (!mono_error_ok (&cfg->error));
13009         goto cleanup;
13010  
13011  exception_exit:
13012         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13013         goto cleanup;
13014
13015  unverified:
13016         set_exception_type_from_invalid_il (cfg, method, ip);
13017         goto cleanup;
13018
13019  cleanup:
13020         g_slist_free (class_inits);
13021         mono_basic_block_free (original_bb);
13022         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13023         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13024         if (cfg->exception_type)
13025                 return -1;
13026         else
13027                 return inline_costs;
13028 }
13029
13030 static int
13031 store_membase_reg_to_store_membase_imm (int opcode)
13032 {
13033         switch (opcode) {
13034         case OP_STORE_MEMBASE_REG:
13035                 return OP_STORE_MEMBASE_IMM;
13036         case OP_STOREI1_MEMBASE_REG:
13037                 return OP_STOREI1_MEMBASE_IMM;
13038         case OP_STOREI2_MEMBASE_REG:
13039                 return OP_STOREI2_MEMBASE_IMM;
13040         case OP_STOREI4_MEMBASE_REG:
13041                 return OP_STOREI4_MEMBASE_IMM;
13042         case OP_STOREI8_MEMBASE_REG:
13043                 return OP_STOREI8_MEMBASE_IMM;
13044         default:
13045                 g_assert_not_reached ();
13046         }
13047
13048         return -1;
13049 }               
13050
13051 int
13052 mono_op_to_op_imm (int opcode)
13053 {
13054         switch (opcode) {
13055         case OP_IADD:
13056                 return OP_IADD_IMM;
13057         case OP_ISUB:
13058                 return OP_ISUB_IMM;
13059         case OP_IDIV:
13060                 return OP_IDIV_IMM;
13061         case OP_IDIV_UN:
13062                 return OP_IDIV_UN_IMM;
13063         case OP_IREM:
13064                 return OP_IREM_IMM;
13065         case OP_IREM_UN:
13066                 return OP_IREM_UN_IMM;
13067         case OP_IMUL:
13068                 return OP_IMUL_IMM;
13069         case OP_IAND:
13070                 return OP_IAND_IMM;
13071         case OP_IOR:
13072                 return OP_IOR_IMM;
13073         case OP_IXOR:
13074                 return OP_IXOR_IMM;
13075         case OP_ISHL:
13076                 return OP_ISHL_IMM;
13077         case OP_ISHR:
13078                 return OP_ISHR_IMM;
13079         case OP_ISHR_UN:
13080                 return OP_ISHR_UN_IMM;
13081
13082         case OP_LADD:
13083                 return OP_LADD_IMM;
13084         case OP_LSUB:
13085                 return OP_LSUB_IMM;
13086         case OP_LAND:
13087                 return OP_LAND_IMM;
13088         case OP_LOR:
13089                 return OP_LOR_IMM;
13090         case OP_LXOR:
13091                 return OP_LXOR_IMM;
13092         case OP_LSHL:
13093                 return OP_LSHL_IMM;
13094         case OP_LSHR:
13095                 return OP_LSHR_IMM;
13096         case OP_LSHR_UN:
13097                 return OP_LSHR_UN_IMM;
13098 #if SIZEOF_REGISTER == 8
13099         case OP_LREM:
13100                 return OP_LREM_IMM;
13101 #endif
13102
13103         case OP_COMPARE:
13104                 return OP_COMPARE_IMM;
13105         case OP_ICOMPARE:
13106                 return OP_ICOMPARE_IMM;
13107         case OP_LCOMPARE:
13108                 return OP_LCOMPARE_IMM;
13109
13110         case OP_STORE_MEMBASE_REG:
13111                 return OP_STORE_MEMBASE_IMM;
13112         case OP_STOREI1_MEMBASE_REG:
13113                 return OP_STOREI1_MEMBASE_IMM;
13114         case OP_STOREI2_MEMBASE_REG:
13115                 return OP_STOREI2_MEMBASE_IMM;
13116         case OP_STOREI4_MEMBASE_REG:
13117                 return OP_STOREI4_MEMBASE_IMM;
13118
13119 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13120         case OP_X86_PUSH:
13121                 return OP_X86_PUSH_IMM;
13122         case OP_X86_COMPARE_MEMBASE_REG:
13123                 return OP_X86_COMPARE_MEMBASE_IMM;
13124 #endif
13125 #if defined(TARGET_AMD64)
13126         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13127                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13128 #endif
13129         case OP_VOIDCALL_REG:
13130                 return OP_VOIDCALL;
13131         case OP_CALL_REG:
13132                 return OP_CALL;
13133         case OP_LCALL_REG:
13134                 return OP_LCALL;
13135         case OP_FCALL_REG:
13136                 return OP_FCALL;
13137         case OP_LOCALLOC:
13138                 return OP_LOCALLOC_IMM;
13139         }
13140
13141         return -1;
13142 }
13143
13144 static int
13145 ldind_to_load_membase (int opcode)
13146 {
13147         switch (opcode) {
13148         case CEE_LDIND_I1:
13149                 return OP_LOADI1_MEMBASE;
13150         case CEE_LDIND_U1:
13151                 return OP_LOADU1_MEMBASE;
13152         case CEE_LDIND_I2:
13153                 return OP_LOADI2_MEMBASE;
13154         case CEE_LDIND_U2:
13155                 return OP_LOADU2_MEMBASE;
13156         case CEE_LDIND_I4:
13157                 return OP_LOADI4_MEMBASE;
13158         case CEE_LDIND_U4:
13159                 return OP_LOADU4_MEMBASE;
13160         case CEE_LDIND_I:
13161                 return OP_LOAD_MEMBASE;
13162         case CEE_LDIND_REF:
13163                 return OP_LOAD_MEMBASE;
13164         case CEE_LDIND_I8:
13165                 return OP_LOADI8_MEMBASE;
13166         case CEE_LDIND_R4:
13167                 return OP_LOADR4_MEMBASE;
13168         case CEE_LDIND_R8:
13169                 return OP_LOADR8_MEMBASE;
13170         default:
13171                 g_assert_not_reached ();
13172         }
13173
13174         return -1;
13175 }
13176
13177 static int
13178 stind_to_store_membase (int opcode)
13179 {
13180         switch (opcode) {
13181         case CEE_STIND_I1:
13182                 return OP_STOREI1_MEMBASE_REG;
13183         case CEE_STIND_I2:
13184                 return OP_STOREI2_MEMBASE_REG;
13185         case CEE_STIND_I4:
13186                 return OP_STOREI4_MEMBASE_REG;
13187         case CEE_STIND_I:
13188         case CEE_STIND_REF:
13189                 return OP_STORE_MEMBASE_REG;
13190         case CEE_STIND_I8:
13191                 return OP_STOREI8_MEMBASE_REG;
13192         case CEE_STIND_R4:
13193                 return OP_STORER4_MEMBASE_REG;
13194         case CEE_STIND_R8:
13195                 return OP_STORER8_MEMBASE_REG;
13196         default:
13197                 g_assert_not_reached ();
13198         }
13199
13200         return -1;
13201 }
13202
13203 int
13204 mono_load_membase_to_load_mem (int opcode)
13205 {
13206         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13207 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13208         switch (opcode) {
13209         case OP_LOAD_MEMBASE:
13210                 return OP_LOAD_MEM;
13211         case OP_LOADU1_MEMBASE:
13212                 return OP_LOADU1_MEM;
13213         case OP_LOADU2_MEMBASE:
13214                 return OP_LOADU2_MEM;
13215         case OP_LOADI4_MEMBASE:
13216                 return OP_LOADI4_MEM;
13217         case OP_LOADU4_MEMBASE:
13218                 return OP_LOADU4_MEM;
13219 #if SIZEOF_REGISTER == 8
13220         case OP_LOADI8_MEMBASE:
13221                 return OP_LOADI8_MEM;
13222 #endif
13223         }
13224 #endif
13225
13226         return -1;
13227 }
13228
13229 static inline int
13230 op_to_op_dest_membase (int store_opcode, int opcode)
13231 {
13232 #if defined(TARGET_X86)
13233         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13234                 return -1;
13235
13236         switch (opcode) {
13237         case OP_IADD:
13238                 return OP_X86_ADD_MEMBASE_REG;
13239         case OP_ISUB:
13240                 return OP_X86_SUB_MEMBASE_REG;
13241         case OP_IAND:
13242                 return OP_X86_AND_MEMBASE_REG;
13243         case OP_IOR:
13244                 return OP_X86_OR_MEMBASE_REG;
13245         case OP_IXOR:
13246                 return OP_X86_XOR_MEMBASE_REG;
13247         case OP_ADD_IMM:
13248         case OP_IADD_IMM:
13249                 return OP_X86_ADD_MEMBASE_IMM;
13250         case OP_SUB_IMM:
13251         case OP_ISUB_IMM:
13252                 return OP_X86_SUB_MEMBASE_IMM;
13253         case OP_AND_IMM:
13254         case OP_IAND_IMM:
13255                 return OP_X86_AND_MEMBASE_IMM;
13256         case OP_OR_IMM:
13257         case OP_IOR_IMM:
13258                 return OP_X86_OR_MEMBASE_IMM;
13259         case OP_XOR_IMM:
13260         case OP_IXOR_IMM:
13261                 return OP_X86_XOR_MEMBASE_IMM;
13262         case OP_MOVE:
13263                 return OP_NOP;
13264         }
13265 #endif
13266
13267 #if defined(TARGET_AMD64)
13268         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13269                 return -1;
13270
13271         switch (opcode) {
13272         case OP_IADD:
13273                 return OP_X86_ADD_MEMBASE_REG;
13274         case OP_ISUB:
13275                 return OP_X86_SUB_MEMBASE_REG;
13276         case OP_IAND:
13277                 return OP_X86_AND_MEMBASE_REG;
13278         case OP_IOR:
13279                 return OP_X86_OR_MEMBASE_REG;
13280         case OP_IXOR:
13281                 return OP_X86_XOR_MEMBASE_REG;
13282         case OP_IADD_IMM:
13283                 return OP_X86_ADD_MEMBASE_IMM;
13284         case OP_ISUB_IMM:
13285                 return OP_X86_SUB_MEMBASE_IMM;
13286         case OP_IAND_IMM:
13287                 return OP_X86_AND_MEMBASE_IMM;
13288         case OP_IOR_IMM:
13289                 return OP_X86_OR_MEMBASE_IMM;
13290         case OP_IXOR_IMM:
13291                 return OP_X86_XOR_MEMBASE_IMM;
13292         case OP_LADD:
13293                 return OP_AMD64_ADD_MEMBASE_REG;
13294         case OP_LSUB:
13295                 return OP_AMD64_SUB_MEMBASE_REG;
13296         case OP_LAND:
13297                 return OP_AMD64_AND_MEMBASE_REG;
13298         case OP_LOR:
13299                 return OP_AMD64_OR_MEMBASE_REG;
13300         case OP_LXOR:
13301                 return OP_AMD64_XOR_MEMBASE_REG;
13302         case OP_ADD_IMM:
13303         case OP_LADD_IMM:
13304                 return OP_AMD64_ADD_MEMBASE_IMM;
13305         case OP_SUB_IMM:
13306         case OP_LSUB_IMM:
13307                 return OP_AMD64_SUB_MEMBASE_IMM;
13308         case OP_AND_IMM:
13309         case OP_LAND_IMM:
13310                 return OP_AMD64_AND_MEMBASE_IMM;
13311         case OP_OR_IMM:
13312         case OP_LOR_IMM:
13313                 return OP_AMD64_OR_MEMBASE_IMM;
13314         case OP_XOR_IMM:
13315         case OP_LXOR_IMM:
13316                 return OP_AMD64_XOR_MEMBASE_IMM;
13317         case OP_MOVE:
13318                 return OP_NOP;
13319         }
13320 #endif
13321
13322         return -1;
13323 }
13324
13325 static inline int
13326 op_to_op_store_membase (int store_opcode, int opcode)
13327 {
13328 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13329         switch (opcode) {
13330         case OP_ICEQ:
13331                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13332                         return OP_X86_SETEQ_MEMBASE;
13333         case OP_CNE:
13334                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13335                         return OP_X86_SETNE_MEMBASE;
13336         }
13337 #endif
13338
13339         return -1;
13340 }
13341
13342 static inline int
13343 op_to_op_src1_membase (int load_opcode, int opcode)
13344 {
13345 #ifdef TARGET_X86
13346         /* FIXME: This has sign extension issues */
13347         /*
13348         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13349                 return OP_X86_COMPARE_MEMBASE8_IMM;
13350         */
13351
13352         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13353                 return -1;
13354
13355         switch (opcode) {
13356         case OP_X86_PUSH:
13357                 return OP_X86_PUSH_MEMBASE;
13358         case OP_COMPARE_IMM:
13359         case OP_ICOMPARE_IMM:
13360                 return OP_X86_COMPARE_MEMBASE_IMM;
13361         case OP_COMPARE:
13362         case OP_ICOMPARE:
13363                 return OP_X86_COMPARE_MEMBASE_REG;
13364         }
13365 #endif
13366
13367 #ifdef TARGET_AMD64
13368         /* FIXME: This has sign extension issues */
13369         /*
13370         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13371                 return OP_X86_COMPARE_MEMBASE8_IMM;
13372         */
13373
13374         switch (opcode) {
13375         case OP_X86_PUSH:
13376 #ifdef __mono_ilp32__
13377                 if (load_opcode == OP_LOADI8_MEMBASE)
13378 #else
13379                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13380 #endif
13381                         return OP_X86_PUSH_MEMBASE;
13382                 break;
13383                 /* FIXME: This only works for 32 bit immediates
13384         case OP_COMPARE_IMM:
13385         case OP_LCOMPARE_IMM:
13386                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13387                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13388                 */
13389         case OP_ICOMPARE_IMM:
13390                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13391                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13392                 break;
13393         case OP_COMPARE:
13394         case OP_LCOMPARE:
13395 #ifdef __mono_ilp32__
13396                 if (load_opcode == OP_LOAD_MEMBASE)
13397                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13398                 if (load_opcode == OP_LOADI8_MEMBASE)
13399 #else
13400                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13401 #endif
13402                         return OP_AMD64_COMPARE_MEMBASE_REG;
13403                 break;
13404         case OP_ICOMPARE:
13405                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13406                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13407                 break;
13408         }
13409 #endif
13410
13411         return -1;
13412 }
13413
13414 static inline int
13415 op_to_op_src2_membase (int load_opcode, int opcode)
13416 {
13417 #ifdef TARGET_X86
13418         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13419                 return -1;
13420         
13421         switch (opcode) {
13422         case OP_COMPARE:
13423         case OP_ICOMPARE:
13424                 return OP_X86_COMPARE_REG_MEMBASE;
13425         case OP_IADD:
13426                 return OP_X86_ADD_REG_MEMBASE;
13427         case OP_ISUB:
13428                 return OP_X86_SUB_REG_MEMBASE;
13429         case OP_IAND:
13430                 return OP_X86_AND_REG_MEMBASE;
13431         case OP_IOR:
13432                 return OP_X86_OR_REG_MEMBASE;
13433         case OP_IXOR:
13434                 return OP_X86_XOR_REG_MEMBASE;
13435         }
13436 #endif
13437
13438 #ifdef TARGET_AMD64
13439 #ifdef __mono_ilp32__
13440         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13441 #else
13442         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13443 #endif
13444                 switch (opcode) {
13445                 case OP_ICOMPARE:
13446                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13447                 case OP_IADD:
13448                         return OP_X86_ADD_REG_MEMBASE;
13449                 case OP_ISUB:
13450                         return OP_X86_SUB_REG_MEMBASE;
13451                 case OP_IAND:
13452                         return OP_X86_AND_REG_MEMBASE;
13453                 case OP_IOR:
13454                         return OP_X86_OR_REG_MEMBASE;
13455                 case OP_IXOR:
13456                         return OP_X86_XOR_REG_MEMBASE;
13457                 }
13458 #ifdef __mono_ilp32__
13459         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13460 #else
13461         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13462 #endif
13463                 switch (opcode) {
13464                 case OP_COMPARE:
13465                 case OP_LCOMPARE:
13466                         return OP_AMD64_COMPARE_REG_MEMBASE;
13467                 case OP_LADD:
13468                         return OP_AMD64_ADD_REG_MEMBASE;
13469                 case OP_LSUB:
13470                         return OP_AMD64_SUB_REG_MEMBASE;
13471                 case OP_LAND:
13472                         return OP_AMD64_AND_REG_MEMBASE;
13473                 case OP_LOR:
13474                         return OP_AMD64_OR_REG_MEMBASE;
13475                 case OP_LXOR:
13476                         return OP_AMD64_XOR_REG_MEMBASE;
13477                 }
13478         }
13479 #endif
13480
13481         return -1;
13482 }
13483
13484 int
13485 mono_op_to_op_imm_noemul (int opcode)
13486 {
13487         switch (opcode) {
13488 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13489         case OP_LSHR:
13490         case OP_LSHL:
13491         case OP_LSHR_UN:
13492                 return -1;
13493 #endif
13494 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13495         case OP_IDIV:
13496         case OP_IDIV_UN:
13497         case OP_IREM:
13498         case OP_IREM_UN:
13499                 return -1;
13500 #endif
13501 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13502         case OP_IMUL:
13503                 return -1;
13504 #endif
13505         default:
13506                 return mono_op_to_op_imm (opcode);
13507         }
13508 }
13509
13510 /**
13511  * mono_handle_global_vregs:
13512  *
13513  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13514  * for them.
13515  */
13516 void
13517 mono_handle_global_vregs (MonoCompile *cfg)
13518 {
13519         gint32 *vreg_to_bb;
13520         MonoBasicBlock *bb;
13521         int i, pos;
13522
13523         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13524
13525 #ifdef MONO_ARCH_SIMD_INTRINSICS
13526         if (cfg->uses_simd_intrinsics)
13527                 mono_simd_simplify_indirection (cfg);
13528 #endif
13529
13530         /* Find local vregs used in more than one bb */
13531         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13532                 MonoInst *ins = bb->code;       
13533                 int block_num = bb->block_num;
13534
13535                 if (cfg->verbose_level > 2)
13536                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13537
13538                 cfg->cbb = bb;
13539                 for (; ins; ins = ins->next) {
13540                         const char *spec = INS_INFO (ins->opcode);
13541                         int regtype = 0, regindex;
13542                         gint32 prev_bb;
13543
13544                         if (G_UNLIKELY (cfg->verbose_level > 2))
13545                                 mono_print_ins (ins);
13546
13547                         g_assert (ins->opcode >= MONO_CEE_LAST);
13548
13549                         for (regindex = 0; regindex < 4; regindex ++) {
13550                                 int vreg = 0;
13551
13552                                 if (regindex == 0) {
13553                                         regtype = spec [MONO_INST_DEST];
13554                                         if (regtype == ' ')
13555                                                 continue;
13556                                         vreg = ins->dreg;
13557                                 } else if (regindex == 1) {
13558                                         regtype = spec [MONO_INST_SRC1];
13559                                         if (regtype == ' ')
13560                                                 continue;
13561                                         vreg = ins->sreg1;
13562                                 } else if (regindex == 2) {
13563                                         regtype = spec [MONO_INST_SRC2];
13564                                         if (regtype == ' ')
13565                                                 continue;
13566                                         vreg = ins->sreg2;
13567                                 } else if (regindex == 3) {
13568                                         regtype = spec [MONO_INST_SRC3];
13569                                         if (regtype == ' ')
13570                                                 continue;
13571                                         vreg = ins->sreg3;
13572                                 }
13573
13574 #if SIZEOF_REGISTER == 4
13575                                 /* In the LLVM case, the long opcodes are not decomposed */
13576                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13577                                         /*
13578                                          * Since some instructions reference the original long vreg,
13579                                          * and some reference the two component vregs, it is quite hard
13580                                          * to determine when it needs to be global. So be conservative.
13581                                          */
13582                                         if (!get_vreg_to_inst (cfg, vreg)) {
13583                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13584
13585                                                 if (cfg->verbose_level > 2)
13586                                                         printf ("LONG VREG R%d made global.\n", vreg);
13587                                         }
13588
13589                                         /*
13590                                          * Make the component vregs volatile since the optimizations can
13591                                          * get confused otherwise.
13592                                          */
13593                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13594                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13595                                 }
13596 #endif
13597
13598                                 g_assert (vreg != -1);
13599
13600                                 prev_bb = vreg_to_bb [vreg];
13601                                 if (prev_bb == 0) {
13602                                         /* 0 is a valid block num */
13603                                         vreg_to_bb [vreg] = block_num + 1;
13604                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13605                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13606                                                 continue;
13607
13608                                         if (!get_vreg_to_inst (cfg, vreg)) {
13609                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13610                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13611
13612                                                 switch (regtype) {
13613                                                 case 'i':
13614                                                         if (vreg_is_ref (cfg, vreg))
13615                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13616                                                         else
13617                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13618                                                         break;
13619                                                 case 'l':
13620                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13621                                                         break;
13622                                                 case 'f':
13623                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13624                                                         break;
13625                                                 case 'v':
13626                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13627                                                         break;
13628                                                 default:
13629                                                         g_assert_not_reached ();
13630                                                 }
13631                                         }
13632
13633                                         /* Flag as having been used in more than one bb */
13634                                         vreg_to_bb [vreg] = -1;
13635                                 }
13636                         }
13637                 }
13638         }
13639
13640         /* If a variable is used in only one bblock, convert it into a local vreg */
13641         for (i = 0; i < cfg->num_varinfo; i++) {
13642                 MonoInst *var = cfg->varinfo [i];
13643                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13644
13645                 switch (var->type) {
13646                 case STACK_I4:
13647                 case STACK_OBJ:
13648                 case STACK_PTR:
13649                 case STACK_MP:
13650                 case STACK_VTYPE:
13651 #if SIZEOF_REGISTER == 8
13652                 case STACK_I8:
13653 #endif
13654 #if !defined(TARGET_X86)
13655                 /* Enabling this screws up the fp stack on x86 */
13656                 case STACK_R8:
13657 #endif
13658                         if (mono_arch_is_soft_float ())
13659                                 break;
13660
13661                         /* Arguments are implicitly global */
13662                         /* Putting R4 vars into registers doesn't work currently */
13663                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13664                         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 && var != cfg->gsharedvt_info_var && var != cfg->gsharedvt_locals_var && var != cfg->lmf_addr_var) {
13665                                 /* 
13666                                  * Make that the variable's liveness interval doesn't contain a call, since
13667                                  * that would cause the lvreg to be spilled, making the whole optimization
13668                                  * useless.
13669                                  */
13670                                 /* This is too slow for JIT compilation */
13671 #if 0
13672                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13673                                         MonoInst *ins;
13674                                         int def_index, call_index, ins_index;
13675                                         gboolean spilled = FALSE;
13676
13677                                         def_index = -1;
13678                                         call_index = -1;
13679                                         ins_index = 0;
13680                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13681                                                 const char *spec = INS_INFO (ins->opcode);
13682
13683                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13684                                                         def_index = ins_index;
13685
13686                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13687                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13688                                                         if (call_index > def_index) {
13689                                                                 spilled = TRUE;
13690                                                                 break;
13691                                                         }
13692                                                 }
13693
13694                                                 if (MONO_IS_CALL (ins))
13695                                                         call_index = ins_index;
13696
13697                                                 ins_index ++;
13698                                         }
13699
13700                                         if (spilled)
13701                                                 break;
13702                                 }
13703 #endif
13704
13705                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13706                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13707                                 var->flags |= MONO_INST_IS_DEAD;
13708                                 cfg->vreg_to_inst [var->dreg] = NULL;
13709                         }
13710                         break;
13711                 }
13712         }
13713
13714         /* 
13715          * Compress the varinfo and vars tables so the liveness computation is faster and
13716          * takes up less space.
13717          */
13718         pos = 0;
13719         for (i = 0; i < cfg->num_varinfo; ++i) {
13720                 MonoInst *var = cfg->varinfo [i];
13721                 if (pos < i && cfg->locals_start == i)
13722                         cfg->locals_start = pos;
13723                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13724                         if (pos < i) {
13725                                 cfg->varinfo [pos] = cfg->varinfo [i];
13726                                 cfg->varinfo [pos]->inst_c0 = pos;
13727                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13728                                 cfg->vars [pos].idx = pos;
13729 #if SIZEOF_REGISTER == 4
13730                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13731                                         /* Modify the two component vars too */
13732                                         MonoInst *var1;
13733
13734                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13735                                         var1->inst_c0 = pos;
13736                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13737                                         var1->inst_c0 = pos;
13738                                 }
13739 #endif
13740                         }
13741                         pos ++;
13742                 }
13743         }
13744         cfg->num_varinfo = pos;
13745         if (cfg->locals_start > cfg->num_varinfo)
13746                 cfg->locals_start = cfg->num_varinfo;
13747 }
13748
13749 /**
13750  * mono_spill_global_vars:
13751  *
13752  *   Generate spill code for variables which are not allocated to registers, 
13753  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13754  * code is generated which could be optimized by the local optimization passes.
13755  */
13756 void
13757 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13758 {
13759         MonoBasicBlock *bb;
13760         char spec2 [16];
13761         int orig_next_vreg;
13762         guint32 *vreg_to_lvreg;
13763         guint32 *lvregs;
13764         guint32 i, lvregs_len;
13765         gboolean dest_has_lvreg = FALSE;
13766         guint32 stacktypes [128];
13767         MonoInst **live_range_start, **live_range_end;
13768         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13769         int *gsharedvt_vreg_to_idx = NULL;
13770
13771         *need_local_opts = FALSE;
13772
13773         memset (spec2, 0, sizeof (spec2));
13774
13775         /* FIXME: Move this function to mini.c */
13776         stacktypes ['i'] = STACK_PTR;
13777         stacktypes ['l'] = STACK_I8;
13778         stacktypes ['f'] = STACK_R8;
13779 #ifdef MONO_ARCH_SIMD_INTRINSICS
13780         stacktypes ['x'] = STACK_VTYPE;
13781 #endif
13782
13783 #if SIZEOF_REGISTER == 4
13784         /* Create MonoInsts for longs */
13785         for (i = 0; i < cfg->num_varinfo; i++) {
13786                 MonoInst *ins = cfg->varinfo [i];
13787
13788                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13789                         switch (ins->type) {
13790                         case STACK_R8:
13791                         case STACK_I8: {
13792                                 MonoInst *tree;
13793
13794                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13795                                         break;
13796
13797                                 g_assert (ins->opcode == OP_REGOFFSET);
13798
13799                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13800                                 g_assert (tree);
13801                                 tree->opcode = OP_REGOFFSET;
13802                                 tree->inst_basereg = ins->inst_basereg;
13803                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13804
13805                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13806                                 g_assert (tree);
13807                                 tree->opcode = OP_REGOFFSET;
13808                                 tree->inst_basereg = ins->inst_basereg;
13809                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13810                                 break;
13811                         }
13812                         default:
13813                                 break;
13814                         }
13815                 }
13816         }
13817 #endif
13818
13819         if (cfg->compute_gc_maps) {
13820                 /* registers need liveness info even for !non refs */
13821                 for (i = 0; i < cfg->num_varinfo; i++) {
13822                         MonoInst *ins = cfg->varinfo [i];
13823
13824                         if (ins->opcode == OP_REGVAR)
13825                                 ins->flags |= MONO_INST_GC_TRACK;
13826                 }
13827         }
13828
13829         if (cfg->gsharedvt) {
13830                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13831
13832                 for (i = 0; i < cfg->num_varinfo; ++i) {
13833                         MonoInst *ins = cfg->varinfo [i];
13834                         int idx;
13835
13836                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13837                                 if (i >= cfg->locals_start) {
13838                                         /* Local */
13839                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13840                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13841                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13842                                         ins->inst_imm = idx;
13843                                 } else {
13844                                         /* Arg */
13845                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13846                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13847                                 }
13848                         }
13849                 }
13850         }
13851                 
13852         /* FIXME: widening and truncation */
13853
13854         /*
13855          * As an optimization, when a variable allocated to the stack is first loaded into 
13856          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13857          * the variable again.
13858          */
13859         orig_next_vreg = cfg->next_vreg;
13860         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13861         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13862         lvregs_len = 0;
13863
13864         /* 
13865          * These arrays contain the first and last instructions accessing a given
13866          * variable.
13867          * Since we emit bblocks in the same order we process them here, and we
13868          * don't split live ranges, these will precisely describe the live range of
13869          * the variable, i.e. the instruction range where a valid value can be found
13870          * in the variables location.
13871          * The live range is computed using the liveness info computed by the liveness pass.
13872          * We can't use vmv->range, since that is an abstract live range, and we need
13873          * one which is instruction precise.
13874          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13875          */
13876         /* FIXME: Only do this if debugging info is requested */
13877         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13878         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13879         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13880         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13881         
13882         /* Add spill loads/stores */
13883         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13884                 MonoInst *ins;
13885
13886                 if (cfg->verbose_level > 2)
13887                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13888
13889                 /* Clear vreg_to_lvreg array */
13890                 for (i = 0; i < lvregs_len; i++)
13891                         vreg_to_lvreg [lvregs [i]] = 0;
13892                 lvregs_len = 0;
13893
13894                 cfg->cbb = bb;
13895                 MONO_BB_FOR_EACH_INS (bb, ins) {
13896                         const char *spec = INS_INFO (ins->opcode);
13897                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13898                         gboolean store, no_lvreg;
13899                         int sregs [MONO_MAX_SRC_REGS];
13900
13901                         if (G_UNLIKELY (cfg->verbose_level > 2))
13902                                 mono_print_ins (ins);
13903
13904                         if (ins->opcode == OP_NOP)
13905                                 continue;
13906
13907                         /* 
13908                          * We handle LDADDR here as well, since it can only be decomposed
13909                          * when variable addresses are known.
13910                          */
13911                         if (ins->opcode == OP_LDADDR) {
13912                                 MonoInst *var = ins->inst_p0;
13913
13914                                 if (var->opcode == OP_VTARG_ADDR) {
13915                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13916                                         MonoInst *vtaddr = var->inst_left;
13917                                         if (vtaddr->opcode == OP_REGVAR) {
13918                                                 ins->opcode = OP_MOVE;
13919                                                 ins->sreg1 = vtaddr->dreg;
13920                                         }
13921                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13922                                                 ins->opcode = OP_LOAD_MEMBASE;
13923                                                 ins->inst_basereg = vtaddr->inst_basereg;
13924                                                 ins->inst_offset = vtaddr->inst_offset;
13925                                         } else
13926                                                 NOT_IMPLEMENTED;
13927                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13928                                         /* gsharedvt arg passed by ref */
13929                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13930
13931                                         ins->opcode = OP_LOAD_MEMBASE;
13932                                         ins->inst_basereg = var->inst_basereg;
13933                                         ins->inst_offset = var->inst_offset;
13934                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13935                                         MonoInst *load, *load2, *load3;
13936                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13937                                         int reg1, reg2, reg3;
13938                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13939                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13940
13941                                         /*
13942                                          * gsharedvt local.
13943                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13944                                          */
13945
13946                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13947
13948                                         g_assert (info_var);
13949                                         g_assert (locals_var);
13950
13951                                         /* Mark the instruction used to compute the locals var as used */
13952                                         cfg->gsharedvt_locals_var_ins = NULL;
13953
13954                                         /* Load the offset */
13955                                         if (info_var->opcode == OP_REGOFFSET) {
13956                                                 reg1 = alloc_ireg (cfg);
13957                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13958                                         } else if (info_var->opcode == OP_REGVAR) {
13959                                                 load = NULL;
13960                                                 reg1 = info_var->dreg;
13961                                         } else {
13962                                                 g_assert_not_reached ();
13963                                         }
13964                                         reg2 = alloc_ireg (cfg);
13965                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13966                                         /* Load the locals area address */
13967                                         reg3 = alloc_ireg (cfg);
13968                                         if (locals_var->opcode == OP_REGOFFSET) {
13969                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13970                                         } else if (locals_var->opcode == OP_REGVAR) {
13971                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13972                                         } else {
13973                                                 g_assert_not_reached ();
13974                                         }
13975                                         /* Compute the address */
13976                                         ins->opcode = OP_PADD;
13977                                         ins->sreg1 = reg3;
13978                                         ins->sreg2 = reg2;
13979
13980                                         mono_bblock_insert_before_ins (bb, ins, load3);
13981                                         mono_bblock_insert_before_ins (bb, load3, load2);
13982                                         if (load)
13983                                                 mono_bblock_insert_before_ins (bb, load2, load);
13984                                 } else {
13985                                         g_assert (var->opcode == OP_REGOFFSET);
13986
13987                                         ins->opcode = OP_ADD_IMM;
13988                                         ins->sreg1 = var->inst_basereg;
13989                                         ins->inst_imm = var->inst_offset;
13990                                 }
13991
13992                                 *need_local_opts = TRUE;
13993                                 spec = INS_INFO (ins->opcode);
13994                         }
13995
13996                         if (ins->opcode < MONO_CEE_LAST) {
13997                                 mono_print_ins (ins);
13998                                 g_assert_not_reached ();
13999                         }
14000
14001                         /*
14002                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14003                          * src register.
14004                          * FIXME:
14005                          */
14006                         if (MONO_IS_STORE_MEMBASE (ins)) {
14007                                 tmp_reg = ins->dreg;
14008                                 ins->dreg = ins->sreg2;
14009                                 ins->sreg2 = tmp_reg;
14010                                 store = TRUE;
14011
14012                                 spec2 [MONO_INST_DEST] = ' ';
14013                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14014                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14015                                 spec2 [MONO_INST_SRC3] = ' ';
14016                                 spec = spec2;
14017                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14018                                 g_assert_not_reached ();
14019                         else
14020                                 store = FALSE;
14021                         no_lvreg = FALSE;
14022
14023                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14024                                 printf ("\t %.3s %d", spec, ins->dreg);
14025                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14026                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14027                                         printf (" %d", sregs [srcindex]);
14028                                 printf ("\n");
14029                         }
14030
14031                         /***************/
14032                         /*    DREG     */
14033                         /***************/
14034                         regtype = spec [MONO_INST_DEST];
14035                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14036                         prev_dreg = -1;
14037
14038                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14039                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14040                                 MonoInst *store_ins;
14041                                 int store_opcode;
14042                                 MonoInst *def_ins = ins;
14043                                 int dreg = ins->dreg; /* The original vreg */
14044
14045                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14046
14047                                 if (var->opcode == OP_REGVAR) {
14048                                         ins->dreg = var->dreg;
14049                                 } 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)) {
14050                                         /* 
14051                                          * Instead of emitting a load+store, use a _membase opcode.
14052                                          */
14053                                         g_assert (var->opcode == OP_REGOFFSET);
14054                                         if (ins->opcode == OP_MOVE) {
14055                                                 NULLIFY_INS (ins);
14056                                                 def_ins = NULL;
14057                                         } else {
14058                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14059                                                 ins->inst_basereg = var->inst_basereg;
14060                                                 ins->inst_offset = var->inst_offset;
14061                                                 ins->dreg = -1;
14062                                         }
14063                                         spec = INS_INFO (ins->opcode);
14064                                 } else {
14065                                         guint32 lvreg;
14066
14067                                         g_assert (var->opcode == OP_REGOFFSET);
14068
14069                                         prev_dreg = ins->dreg;
14070
14071                                         /* Invalidate any previous lvreg for this vreg */
14072                                         vreg_to_lvreg [ins->dreg] = 0;
14073
14074                                         lvreg = 0;
14075
14076                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14077                                                 regtype = 'l';
14078                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14079                                         }
14080
14081                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14082
14083 #if SIZEOF_REGISTER != 8
14084                                         if (regtype == 'l') {
14085                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14086                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14087                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14088                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14089                                                 def_ins = store_ins;
14090                                         }
14091                                         else
14092 #endif
14093                                         {
14094                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14095
14096                                                 /* Try to fuse the store into the instruction itself */
14097                                                 /* FIXME: Add more instructions */
14098                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14099                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14100                                                         ins->inst_imm = ins->inst_c0;
14101                                                         ins->inst_destbasereg = var->inst_basereg;
14102                                                         ins->inst_offset = var->inst_offset;
14103                                                         spec = INS_INFO (ins->opcode);
14104                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14105                                                         ins->opcode = store_opcode;
14106                                                         ins->inst_destbasereg = var->inst_basereg;
14107                                                         ins->inst_offset = var->inst_offset;
14108
14109                                                         no_lvreg = TRUE;
14110
14111                                                         tmp_reg = ins->dreg;
14112                                                         ins->dreg = ins->sreg2;
14113                                                         ins->sreg2 = tmp_reg;
14114                                                         store = TRUE;
14115
14116                                                         spec2 [MONO_INST_DEST] = ' ';
14117                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14118                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14119                                                         spec2 [MONO_INST_SRC3] = ' ';
14120                                                         spec = spec2;
14121                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14122                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14123                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14124                                                         ins->dreg = -1;
14125                                                         ins->inst_basereg = var->inst_basereg;
14126                                                         ins->inst_offset = var->inst_offset;
14127                                                         spec = INS_INFO (ins->opcode);
14128                                                 } else {
14129                                                         /* printf ("INS: "); mono_print_ins (ins); */
14130                                                         /* Create a store instruction */
14131                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14132
14133                                                         /* Insert it after the instruction */
14134                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14135
14136                                                         def_ins = store_ins;
14137
14138                                                         /* 
14139                                                          * We can't assign ins->dreg to var->dreg here, since the
14140                                                          * sregs could use it. So set a flag, and do it after
14141                                                          * the sregs.
14142                                                          */
14143                                                         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)))
14144                                                                 dest_has_lvreg = TRUE;
14145                                                 }
14146                                         }
14147                                 }
14148
14149                                 if (def_ins && !live_range_start [dreg]) {
14150                                         live_range_start [dreg] = def_ins;
14151                                         live_range_start_bb [dreg] = bb;
14152                                 }
14153
14154                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14155                                         MonoInst *tmp;
14156
14157                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14158                                         tmp->inst_c1 = dreg;
14159                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14160                                 }
14161                         }
14162
14163                         /************/
14164                         /*  SREGS   */
14165                         /************/
14166                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14167                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14168                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14169                                 sreg = sregs [srcindex];
14170
14171                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14172                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14173                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14174                                         MonoInst *use_ins = ins;
14175                                         MonoInst *load_ins;
14176                                         guint32 load_opcode;
14177
14178                                         if (var->opcode == OP_REGVAR) {
14179                                                 sregs [srcindex] = var->dreg;
14180                                                 //mono_inst_set_src_registers (ins, sregs);
14181                                                 live_range_end [sreg] = use_ins;
14182                                                 live_range_end_bb [sreg] = bb;
14183
14184                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14185                                                         MonoInst *tmp;
14186
14187                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14188                                                         /* var->dreg is a hreg */
14189                                                         tmp->inst_c1 = sreg;
14190                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14191                                                 }
14192
14193                                                 continue;
14194                                         }
14195
14196                                         g_assert (var->opcode == OP_REGOFFSET);
14197                                                 
14198                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14199
14200                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14201
14202                                         if (vreg_to_lvreg [sreg]) {
14203                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14204
14205                                                 /* The variable is already loaded to an lvreg */
14206                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14207                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14208                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14209                                                 //mono_inst_set_src_registers (ins, sregs);
14210                                                 continue;
14211                                         }
14212
14213                                         /* Try to fuse the load into the instruction */
14214                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14215                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14216                                                 sregs [0] = var->inst_basereg;
14217                                                 //mono_inst_set_src_registers (ins, sregs);
14218                                                 ins->inst_offset = var->inst_offset;
14219                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14220                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14221                                                 sregs [1] = var->inst_basereg;
14222                                                 //mono_inst_set_src_registers (ins, sregs);
14223                                                 ins->inst_offset = var->inst_offset;
14224                                         } else {
14225                                                 if (MONO_IS_REAL_MOVE (ins)) {
14226                                                         ins->opcode = OP_NOP;
14227                                                         sreg = ins->dreg;
14228                                                 } else {
14229                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14230
14231                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14232
14233                                                         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) {
14234                                                                 if (var->dreg == prev_dreg) {
14235                                                                         /*
14236                                                                          * sreg refers to the value loaded by the load
14237                                                                          * emitted below, but we need to use ins->dreg
14238                                                                          * since it refers to the store emitted earlier.
14239                                                                          */
14240                                                                         sreg = ins->dreg;
14241                                                                 }
14242                                                                 g_assert (sreg != -1);
14243                                                                 vreg_to_lvreg [var->dreg] = sreg;
14244                                                                 g_assert (lvregs_len < 1024);
14245                                                                 lvregs [lvregs_len ++] = var->dreg;
14246                                                         }
14247                                                 }
14248
14249                                                 sregs [srcindex] = sreg;
14250                                                 //mono_inst_set_src_registers (ins, sregs);
14251
14252 #if SIZEOF_REGISTER != 8
14253                                                 if (regtype == 'l') {
14254                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14255                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14256                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14257                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14258                                                         use_ins = load_ins;
14259                                                 }
14260                                                 else
14261 #endif
14262                                                 {
14263 #if SIZEOF_REGISTER == 4
14264                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14265 #endif
14266                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14267                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14268                                                         use_ins = load_ins;
14269                                                 }
14270                                         }
14271
14272                                         if (var->dreg < orig_next_vreg) {
14273                                                 live_range_end [var->dreg] = use_ins;
14274                                                 live_range_end_bb [var->dreg] = bb;
14275                                         }
14276
14277                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14278                                                 MonoInst *tmp;
14279
14280                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14281                                                 tmp->inst_c1 = var->dreg;
14282                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14283                                         }
14284                                 }
14285                         }
14286                         mono_inst_set_src_registers (ins, sregs);
14287
14288                         if (dest_has_lvreg) {
14289                                 g_assert (ins->dreg != -1);
14290                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14291                                 g_assert (lvregs_len < 1024);
14292                                 lvregs [lvregs_len ++] = prev_dreg;
14293                                 dest_has_lvreg = FALSE;
14294                         }
14295
14296                         if (store) {
14297                                 tmp_reg = ins->dreg;
14298                                 ins->dreg = ins->sreg2;
14299                                 ins->sreg2 = tmp_reg;
14300                         }
14301
14302                         if (MONO_IS_CALL (ins)) {
14303                                 /* Clear vreg_to_lvreg array */
14304                                 for (i = 0; i < lvregs_len; i++)
14305                                         vreg_to_lvreg [lvregs [i]] = 0;
14306                                 lvregs_len = 0;
14307                         } else if (ins->opcode == OP_NOP) {
14308                                 ins->dreg = -1;
14309                                 MONO_INST_NULLIFY_SREGS (ins);
14310                         }
14311
14312                         if (cfg->verbose_level > 2)
14313                                 mono_print_ins_index (1, ins);
14314                 }
14315
14316                 /* Extend the live range based on the liveness info */
14317                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14318                         for (i = 0; i < cfg->num_varinfo; i ++) {
14319                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14320
14321                                 if (vreg_is_volatile (cfg, vi->vreg))
14322                                         /* The liveness info is incomplete */
14323                                         continue;
14324
14325                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14326                                         /* Live from at least the first ins of this bb */
14327                                         live_range_start [vi->vreg] = bb->code;
14328                                         live_range_start_bb [vi->vreg] = bb;
14329                                 }
14330
14331                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14332                                         /* Live at least until the last ins of this bb */
14333                                         live_range_end [vi->vreg] = bb->last_ins;
14334                                         live_range_end_bb [vi->vreg] = bb;
14335                                 }
14336                         }
14337                 }
14338         }
14339         
14340 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14341         /*
14342          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14343          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14344          */
14345         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14346                 for (i = 0; i < cfg->num_varinfo; ++i) {
14347                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14348                         MonoInst *ins;
14349
14350                         if (live_range_start [vreg]) {
14351                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14352                                 ins->inst_c0 = i;
14353                                 ins->inst_c1 = vreg;
14354                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14355                         }
14356                         if (live_range_end [vreg]) {
14357                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14358                                 ins->inst_c0 = i;
14359                                 ins->inst_c1 = vreg;
14360                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14361                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14362                                 else
14363                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14364                         }
14365                 }
14366         }
14367 #endif
14368
14369         if (cfg->gsharedvt_locals_var_ins) {
14370                 /* Nullify if unused */
14371                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14372                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14373         }
14374
14375         g_free (live_range_start);
14376         g_free (live_range_end);
14377         g_free (live_range_start_bb);
14378         g_free (live_range_end_bb);
14379 }
14380
14381 /**
14382  * FIXME:
14383  * - use 'iadd' instead of 'int_add'
14384  * - handling ovf opcodes: decompose in method_to_ir.
14385  * - unify iregs/fregs
14386  *   -> partly done, the missing parts are:
14387  *   - a more complete unification would involve unifying the hregs as well, so
14388  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14389  *     would no longer map to the machine hregs, so the code generators would need to
14390  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14391  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14392  *     fp/non-fp branches speeds it up by about 15%.
14393  * - use sext/zext opcodes instead of shifts
14394  * - add OP_ICALL
14395  * - get rid of TEMPLOADs if possible and use vregs instead
14396  * - clean up usage of OP_P/OP_ opcodes
14397  * - cleanup usage of DUMMY_USE
14398  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14399  *   stack
14400  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14401  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14402  * - make sure handle_stack_args () is called before the branch is emitted
14403  * - when the new IR is done, get rid of all unused stuff
14404  * - COMPARE/BEQ as separate instructions or unify them ?
14405  *   - keeping them separate allows specialized compare instructions like
14406  *     compare_imm, compare_membase
14407  *   - most back ends unify fp compare+branch, fp compare+ceq
14408  * - integrate mono_save_args into inline_method
14409  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14410  * - handle long shift opts on 32 bit platforms somehow: they require 
14411  *   3 sregs (2 for arg1 and 1 for arg2)
14412  * - make byref a 'normal' type.
14413  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14414  *   variable if needed.
14415  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14416  *   like inline_method.
14417  * - remove inlining restrictions
14418  * - fix LNEG and enable cfold of INEG
14419  * - generalize x86 optimizations like ldelema as a peephole optimization
14420  * - add store_mem_imm for amd64
14421  * - optimize the loading of the interruption flag in the managed->native wrappers
14422  * - avoid special handling of OP_NOP in passes
14423  * - move code inserting instructions into one function/macro.
14424  * - try a coalescing phase after liveness analysis
14425  * - add float -> vreg conversion + local optimizations on !x86
14426  * - figure out how to handle decomposed branches during optimizations, ie.
14427  *   compare+branch, op_jump_table+op_br etc.
14428  * - promote RuntimeXHandles to vregs
14429  * - vtype cleanups:
14430  *   - add a NEW_VARLOADA_VREG macro
14431  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14432  *   accessing vtype fields.
14433  * - get rid of I8CONST on 64 bit platforms
14434  * - dealing with the increase in code size due to branches created during opcode
14435  *   decomposition:
14436  *   - use extended basic blocks
14437  *     - all parts of the JIT
14438  *     - handle_global_vregs () && local regalloc
14439  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14440  * - sources of increase in code size:
14441  *   - vtypes
14442  *   - long compares
14443  *   - isinst and castclass
14444  *   - lvregs not allocated to global registers even if used multiple times
14445  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14446  *   meaningful.
14447  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14448  * - add all micro optimizations from the old JIT
14449  * - put tree optimizations into the deadce pass
14450  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14451  *   specific function.
14452  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14453  *   fcompare + branchCC.
14454  * - create a helper function for allocating a stack slot, taking into account 
14455  *   MONO_CFG_HAS_SPILLUP.
14456  * - merge r68207.
14457  * - merge the ia64 switch changes.
14458  * - optimize mono_regstate2_alloc_int/float.
14459  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14460  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14461  *   parts of the tree could be separated by other instructions, killing the tree
14462  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14463  *   instructions if the result of the load is used multiple times ?
14464  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14465  * - LAST MERGE: 108395.
14466  * - when returning vtypes in registers, generate IR and append it to the end of the
14467  *   last bb instead of doing it in the epilog.
14468  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14469  */
14470
14471 /*
14472
14473 NOTES
14474 -----
14475
14476 - When to decompose opcodes:
14477   - earlier: this makes some optimizations hard to implement, since the low level IR
14478   no longer contains the neccessary information. But it is easier to do.
14479   - later: harder to implement, enables more optimizations.
14480 - Branches inside bblocks:
14481   - created when decomposing complex opcodes. 
14482     - branches to another bblock: harmless, but not tracked by the branch 
14483       optimizations, so need to branch to a label at the start of the bblock.
14484     - branches to inside the same bblock: very problematic, trips up the local
14485       reg allocator. Can be fixed by spitting the current bblock, but that is a
14486       complex operation, since some local vregs can become global vregs etc.
14487 - Local/global vregs:
14488   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14489     local register allocator.
14490   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14491     structure, created by mono_create_var (). Assigned to hregs or the stack by
14492     the global register allocator.
14493 - When to do optimizations like alu->alu_imm:
14494   - earlier -> saves work later on since the IR will be smaller/simpler
14495   - later -> can work on more instructions
14496 - Handling of valuetypes:
14497   - When a vtype is pushed on the stack, a new temporary is created, an 
14498     instruction computing its address (LDADDR) is emitted and pushed on
14499     the stack. Need to optimize cases when the vtype is used immediately as in
14500     argument passing, stloc etc.
14501 - Instead of the to_end stuff in the old JIT, simply call the function handling
14502   the values on the stack before emitting the last instruction of the bb.
14503 */
14504
14505 #endif /* DISABLE_JIT */