[jit] Use mini_get_underlying_type () in a few more places.
[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 context_used, 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         /*
3297          * This check breaks with spilled vars... need to handle it during verification anyway.
3298          * g_assert (klass && klass == src->klass && klass == dest->klass);
3299          */
3300
3301         if (mini_is_gsharedvt_klass (cfg, klass)) {
3302                 g_assert (!native);
3303                 context_used = mini_class_check_context_used (cfg, klass);
3304                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3305                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3306         }
3307
3308         if (native)
3309                 n = mono_class_native_size (klass, &align);
3310         else
3311                 n = mono_class_value_size (klass, &align);
3312
3313         /* if native is true there should be no references in the struct */
3314         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3315                 /* Avoid barriers when storing to the stack */
3316                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3317                           (dest->opcode == OP_LDADDR))) {
3318                         int context_used;
3319
3320                         iargs [0] = dest;
3321                         iargs [1] = src;
3322
3323                         context_used = mini_class_check_context_used (cfg, klass);
3324
3325                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3326                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3327                                 return;
3328                         } else if (context_used) {
3329                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3330                         }  else {
3331                                 if (cfg->compile_aot) {
3332                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3333                                 } else {
3334                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3335                                         mono_class_compute_gc_descriptor (klass);
3336                                 }
3337                         }
3338
3339                         if (size_ins)
3340                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3341                         else
3342                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3343                         return;
3344                 }
3345         }
3346
3347         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3348                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3349                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3350         } else {
3351                 iargs [0] = dest;
3352                 iargs [1] = src;
3353                 if (size_ins)
3354                         iargs [2] = size_ins;
3355                 else
3356                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3357                 
3358                 memcpy_method = get_memcpy_method ();
3359                 if (memcpy_ins)
3360                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3361                 else
3362                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3363         }
3364 }
3365
3366 static MonoMethod*
3367 get_memset_method (void)
3368 {
3369         static MonoMethod *memset_method = NULL;
3370         if (!memset_method) {
3371                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3372                 if (!memset_method)
3373                         g_error ("Old corlib found. Install a new one");
3374         }
3375         return memset_method;
3376 }
3377
3378 void
3379 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3380 {
3381         MonoInst *iargs [3];
3382         int n, context_used;
3383         guint32 align;
3384         MonoMethod *memset_method;
3385         MonoInst *size_ins = NULL;
3386         MonoInst *bzero_ins = NULL;
3387         static MonoMethod *bzero_method;
3388
3389         /* FIXME: Optimize this for the case when dest is an LDADDR */
3390
3391         mono_class_init (klass);
3392         if (mini_is_gsharedvt_klass (cfg, klass)) {
3393                 context_used = mini_class_check_context_used (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                 MonoInst *var;
3952
3953                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3954
3955                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3956                 unbox_sig->ret = &klass->byval_arg;
3957                 unbox_sig->param_count = 1;
3958                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3959                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3960
3961                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3962                 addr->dreg = addr_reg;
3963         }
3964
3965         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3966
3967         /* End */
3968         MONO_START_BB (cfg, end_bb);
3969
3970         /* LDOBJ */
3971         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3972
3973         *out_cbb = cfg->cbb;
3974
3975         return ins;
3976 }
3977
3978 /*
3979  * Returns NULL and set the cfg exception on error.
3980  */
3981 static MonoInst*
3982 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3983 {
3984         MonoInst *iargs [2];
3985         void *alloc_ftn;
3986
3987         if (context_used) {
3988                 MonoInst *data;
3989                 int rgctx_info;
3990                 MonoInst *iargs [2];
3991                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3992
3993                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3994
3995                 if (cfg->opt & MONO_OPT_SHARED)
3996                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3997                 else
3998                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3999                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4000
4001                 if (cfg->opt & MONO_OPT_SHARED) {
4002                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4003                         iargs [1] = data;
4004                         alloc_ftn = mono_object_new;
4005                 } else {
4006                         iargs [0] = data;
4007                         alloc_ftn = mono_object_new_specific;
4008                 }
4009
4010                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4011                         if (known_instance_size)
4012                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4013                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4014                 }
4015
4016                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4017         }
4018
4019         if (cfg->opt & MONO_OPT_SHARED) {
4020                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4021                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4022
4023                 alloc_ftn = mono_object_new;
4024         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4025                 /* This happens often in argument checking code, eg. throw new FooException... */
4026                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4027                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4028                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4029         } else {
4030                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4031                 MonoMethod *managed_alloc = NULL;
4032                 gboolean pass_lw;
4033
4034                 if (!vtable) {
4035                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4036                         cfg->exception_ptr = klass;
4037                         return NULL;
4038                 }
4039
4040 #ifndef MONO_CROSS_COMPILE
4041                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4042 #endif
4043
4044                 if (managed_alloc) {
4045                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4046                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4047                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4048                 }
4049                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4050                 if (pass_lw) {
4051                         guint32 lw = vtable->klass->instance_size;
4052                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4053                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4054                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4055                 }
4056                 else {
4057                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4058                 }
4059         }
4060
4061         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4062 }
4063         
4064 /*
4065  * Returns NULL and set the cfg exception on error.
4066  */     
4067 static MonoInst*
4068 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
4069 {
4070         MonoInst *alloc, *ins;
4071
4072         *out_cbb = cfg->cbb;
4073
4074         if (mono_class_is_nullable (klass)) {
4075                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4076
4077                 if (context_used) {
4078                         /* FIXME: What if the class is shared?  We might not
4079                            have to get the method address from the RGCTX. */
4080                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4081                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4082                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4083
4084                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4085                 } else {
4086                         gboolean pass_vtable, pass_mrgctx;
4087                         MonoInst *rgctx_arg = NULL;
4088
4089                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4090                         g_assert (!pass_mrgctx);
4091
4092                         if (pass_vtable) {
4093                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4094
4095                                 g_assert (vtable);
4096                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4097                         }
4098
4099                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4100                 }
4101         }
4102
4103         if (mini_is_gsharedvt_klass (cfg, klass)) {
4104                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4105                 MonoInst *res, *is_ref, *src_var, *addr;
4106                 int addr_reg, dreg;
4107
4108                 dreg = alloc_ireg (cfg);
4109
4110                 NEW_BBLOCK (cfg, is_ref_bb);
4111                 NEW_BBLOCK (cfg, is_nullable_bb);
4112                 NEW_BBLOCK (cfg, end_bb);
4113                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4114                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4115                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4116
4117                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4118                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4119
4120                 /* Non-ref case */
4121                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4122                 if (!alloc)
4123                         return NULL;
4124                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4125                 ins->opcode = OP_STOREV_MEMBASE;
4126
4127                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4128                 res->type = STACK_OBJ;
4129                 res->klass = klass;
4130                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4131                 
4132                 /* Ref case */
4133                 MONO_START_BB (cfg, is_ref_bb);
4134                 addr_reg = alloc_ireg (cfg);
4135
4136                 /* val is a vtype, so has to load the value manually */
4137                 src_var = get_vreg_to_inst (cfg, val->dreg);
4138                 if (!src_var)
4139                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4140                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4141                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4142                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4143
4144                 /* Nullable case */
4145                 MONO_START_BB (cfg, is_nullable_bb);
4146
4147                 {
4148                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4149                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4150                         MonoInst *box_call;
4151                         MonoMethodSignature *box_sig;
4152
4153                         /*
4154                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4155                          * construct that method at JIT time, so have to do things by hand.
4156                          */
4157                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4158                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4159                         box_sig->param_count = 1;
4160                         box_sig->params [0] = &klass->byval_arg;
4161                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4162                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4163                         res->type = STACK_OBJ;
4164                         res->klass = klass;
4165                 }
4166
4167                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4168
4169                 MONO_START_BB (cfg, end_bb);
4170
4171                 *out_cbb = cfg->cbb;
4172
4173                 return res;
4174         } else {
4175                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4176                 if (!alloc)
4177                         return NULL;
4178
4179                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4180                 return alloc;
4181         }
4182 }
4183
4184
4185 static gboolean
4186 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4187 {
4188         int i;
4189         MonoGenericContainer *container;
4190         MonoGenericInst *ginst;
4191
4192         if (klass->generic_class) {
4193                 container = klass->generic_class->container_class->generic_container;
4194                 ginst = klass->generic_class->context.class_inst;
4195         } else if (klass->generic_container && context_used) {
4196                 container = klass->generic_container;
4197                 ginst = container->context.class_inst;
4198         } else {
4199                 return FALSE;
4200         }
4201
4202         for (i = 0; i < container->type_argc; ++i) {
4203                 MonoType *type;
4204                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4205                         continue;
4206                 type = ginst->type_argv [i];
4207                 if (mini_type_is_reference (cfg, type))
4208                         return TRUE;
4209         }
4210         return FALSE;
4211 }
4212
4213 #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)
4214
4215 static MonoInst*
4216 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4217 {
4218         MonoMethod *mono_castclass;
4219         MonoInst *res;
4220
4221         mono_castclass = mono_marshal_get_castclass_with_cache ();
4222
4223         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4224         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4225         reset_cast_details (cfg);
4226         *out_bblock = cfg->cbb;
4227
4228         return res;
4229 }
4230
4231 static MonoInst*
4232 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4233 {
4234         MonoInst *args [3];
4235         int idx;
4236
4237         /* obj */
4238         args [0] = obj;
4239
4240         /* klass */
4241         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4242
4243         /* inline cache*/
4244         if (cfg->compile_aot) {
4245                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4246                 cfg->castclass_cache_index ++;
4247                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4248                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4249         } else {
4250                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4251         }
4252
4253         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4254
4255         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4256 }
4257
4258 /*
4259  * Returns NULL and set the cfg exception on error.
4260  */
4261 static MonoInst*
4262 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4263 {
4264         MonoBasicBlock *is_null_bb;
4265         int obj_reg = src->dreg;
4266         int vtable_reg = alloc_preg (cfg);
4267         int context_used;
4268         MonoInst *klass_inst = NULL, *res;
4269         MonoBasicBlock *bblock;
4270
4271         *out_bb = cfg->cbb;
4272
4273         context_used = mini_class_check_context_used (cfg, klass);
4274
4275         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4276                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4277                 (*inline_costs) += 2;
4278                 *out_bb = cfg->cbb;
4279                 return res;
4280         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4281                 MonoMethod *mono_castclass;
4282                 MonoInst *iargs [1];
4283                 int costs;
4284
4285                 mono_castclass = mono_marshal_get_castclass (klass); 
4286                 iargs [0] = src;
4287                                 
4288                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4289                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4290                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4291                 reset_cast_details (cfg);
4292                 CHECK_CFG_EXCEPTION;
4293                 g_assert (costs > 0);
4294                                 
4295                 cfg->real_offset += 5;
4296
4297                 (*inline_costs) += costs;
4298
4299                 *out_bb = cfg->cbb;
4300                 return src;
4301         }
4302
4303         if (context_used) {
4304                 MonoInst *args [3];
4305
4306                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4307                         MonoInst *cache_ins;
4308
4309                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4310
4311                         /* obj */
4312                         args [0] = src;
4313
4314                         /* klass - it's the second element of the cache entry*/
4315                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4316
4317                         /* cache */
4318                         args [2] = cache_ins;
4319
4320                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4321                 }
4322
4323                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4324         }
4325
4326         NEW_BBLOCK (cfg, is_null_bb);
4327
4328         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4329         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4330
4331         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4332
4333         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4334                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4335                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4336         } else {
4337                 int klass_reg = alloc_preg (cfg);
4338
4339                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4340
4341                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4342                         /* the remoting code is broken, access the class for now */
4343                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4344                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4345                                 if (!vt) {
4346                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4347                                         cfg->exception_ptr = klass;
4348                                         return NULL;
4349                                 }
4350                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4351                         } else {
4352                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4353                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4354                         }
4355                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4356                 } else {
4357                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4358                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4359                 }
4360         }
4361
4362         MONO_START_BB (cfg, is_null_bb);
4363
4364         reset_cast_details (cfg);
4365
4366         *out_bb = cfg->cbb;
4367
4368         return src;
4369
4370 exception_exit:
4371         return NULL;
4372 }
4373
4374 /*
4375  * Returns NULL and set the cfg exception on error.
4376  */
4377 static MonoInst*
4378 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4379 {
4380         MonoInst *ins;
4381         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4382         int obj_reg = src->dreg;
4383         int vtable_reg = alloc_preg (cfg);
4384         int res_reg = alloc_ireg_ref (cfg);
4385         MonoInst *klass_inst = NULL;
4386
4387         if (context_used) {
4388                 MonoInst *args [3];
4389
4390                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4391                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4392                         MonoInst *cache_ins;
4393
4394                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4395
4396                         /* obj */
4397                         args [0] = src;
4398
4399                         /* klass - it's the second element of the cache entry*/
4400                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4401
4402                         /* cache */
4403                         args [2] = cache_ins;
4404
4405                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4406                 }
4407
4408                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4409         }
4410
4411         NEW_BBLOCK (cfg, is_null_bb);
4412         NEW_BBLOCK (cfg, false_bb);
4413         NEW_BBLOCK (cfg, end_bb);
4414
4415         /* Do the assignment at the beginning, so the other assignment can be if converted */
4416         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4417         ins->type = STACK_OBJ;
4418         ins->klass = klass;
4419
4420         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4421         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4422
4423         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4424
4425         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4426                 g_assert (!context_used);
4427                 /* the is_null_bb target simply copies the input register to the output */
4428                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4429         } else {
4430                 int klass_reg = alloc_preg (cfg);
4431
4432                 if (klass->rank) {
4433                         int rank_reg = alloc_preg (cfg);
4434                         int eclass_reg = alloc_preg (cfg);
4435
4436                         g_assert (!context_used);
4437                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4438                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4439                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4440                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4441                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4442                         if (klass->cast_class == mono_defaults.object_class) {
4443                                 int parent_reg = alloc_preg (cfg);
4444                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4445                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, 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->parent) {
4449                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4450                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4451                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4452                         } else if (klass->cast_class == mono_defaults.enum_class) {
4453                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4454                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4455                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4456                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4457                         } else {
4458                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4459                                         /* Check that the object is a vector too */
4460                                         int bounds_reg = alloc_preg (cfg);
4461                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4462                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4463                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4464                                 }
4465
4466                                 /* the is_null_bb target simply copies the input register to the output */
4467                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4468                         }
4469                 } else if (mono_class_is_nullable (klass)) {
4470                         g_assert (!context_used);
4471                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4472                         /* the is_null_bb target simply copies the input register to the output */
4473                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4474                 } else {
4475                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4476                                 g_assert (!context_used);
4477                                 /* the remoting code is broken, access the class for now */
4478                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4479                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4480                                         if (!vt) {
4481                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4482                                                 cfg->exception_ptr = klass;
4483                                                 return NULL;
4484                                         }
4485                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4486                                 } else {
4487                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4488                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4489                                 }
4490                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4491                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4492                         } else {
4493                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4494                                 /* the is_null_bb target simply copies the input register to the output */
4495                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4496                         }
4497                 }
4498         }
4499
4500         MONO_START_BB (cfg, false_bb);
4501
4502         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4503         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4504
4505         MONO_START_BB (cfg, is_null_bb);
4506
4507         MONO_START_BB (cfg, end_bb);
4508
4509         return ins;
4510 }
4511
4512 static MonoInst*
4513 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4514 {
4515         /* This opcode takes as input an object reference and a class, and returns:
4516         0) if the object is an instance of the class,
4517         1) if the object is not instance of the class,
4518         2) if the object is a proxy whose type cannot be determined */
4519
4520         MonoInst *ins;
4521 #ifndef DISABLE_REMOTING
4522         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4523 #else
4524         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4525 #endif
4526         int obj_reg = src->dreg;
4527         int dreg = alloc_ireg (cfg);
4528         int tmp_reg;
4529 #ifndef DISABLE_REMOTING
4530         int klass_reg = alloc_preg (cfg);
4531 #endif
4532
4533         NEW_BBLOCK (cfg, true_bb);
4534         NEW_BBLOCK (cfg, false_bb);
4535         NEW_BBLOCK (cfg, end_bb);
4536 #ifndef DISABLE_REMOTING
4537         NEW_BBLOCK (cfg, false2_bb);
4538         NEW_BBLOCK (cfg, no_proxy_bb);
4539 #endif
4540
4541         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4542         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4543
4544         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4545 #ifndef DISABLE_REMOTING
4546                 NEW_BBLOCK (cfg, interface_fail_bb);
4547 #endif
4548
4549                 tmp_reg = alloc_preg (cfg);
4550                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4551 #ifndef DISABLE_REMOTING
4552                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4553                 MONO_START_BB (cfg, interface_fail_bb);
4554                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4555                 
4556                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4557
4558                 tmp_reg = alloc_preg (cfg);
4559                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4560                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4561                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4562 #else
4563                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4564 #endif
4565         } else {
4566 #ifndef DISABLE_REMOTING
4567                 tmp_reg = alloc_preg (cfg);
4568                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4569                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4570
4571                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4572                 tmp_reg = alloc_preg (cfg);
4573                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4575
4576                 tmp_reg = alloc_preg (cfg);             
4577                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4578                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4579                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4580                 
4581                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4582                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4583
4584                 MONO_START_BB (cfg, no_proxy_bb);
4585
4586                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4587 #else
4588                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4589 #endif
4590         }
4591
4592         MONO_START_BB (cfg, false_bb);
4593
4594         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4595         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4596
4597 #ifndef DISABLE_REMOTING
4598         MONO_START_BB (cfg, false2_bb);
4599
4600         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4601         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4602 #endif
4603
4604         MONO_START_BB (cfg, true_bb);
4605
4606         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4607
4608         MONO_START_BB (cfg, end_bb);
4609
4610         /* FIXME: */
4611         MONO_INST_NEW (cfg, ins, OP_ICONST);
4612         ins->dreg = dreg;
4613         ins->type = STACK_I4;
4614
4615         return ins;
4616 }
4617
4618 static MonoInst*
4619 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4620 {
4621         /* This opcode takes as input an object reference and a class, and returns:
4622         0) if the object is an instance of the class,
4623         1) if the object is a proxy whose type cannot be determined
4624         an InvalidCastException exception is thrown otherwhise*/
4625         
4626         MonoInst *ins;
4627 #ifndef DISABLE_REMOTING
4628         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4629 #else
4630         MonoBasicBlock *ok_result_bb;
4631 #endif
4632         int obj_reg = src->dreg;
4633         int dreg = alloc_ireg (cfg);
4634         int tmp_reg = alloc_preg (cfg);
4635
4636 #ifndef DISABLE_REMOTING
4637         int klass_reg = alloc_preg (cfg);
4638         NEW_BBLOCK (cfg, end_bb);
4639 #endif
4640
4641         NEW_BBLOCK (cfg, ok_result_bb);
4642
4643         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4644         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4645
4646         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4647
4648         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4649 #ifndef DISABLE_REMOTING
4650                 NEW_BBLOCK (cfg, interface_fail_bb);
4651         
4652                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4653                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4654                 MONO_START_BB (cfg, interface_fail_bb);
4655                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4656
4657                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4658
4659                 tmp_reg = alloc_preg (cfg);             
4660                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4661                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4662                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4663                 
4664                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4665                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4666 #else
4667                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4668                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4669                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4670 #endif
4671         } else {
4672 #ifndef DISABLE_REMOTING
4673                 NEW_BBLOCK (cfg, no_proxy_bb);
4674
4675                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4676                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4677                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4678
4679                 tmp_reg = alloc_preg (cfg);
4680                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4681                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4682
4683                 tmp_reg = alloc_preg (cfg);
4684                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4685                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4686                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4687
4688                 NEW_BBLOCK (cfg, fail_1_bb);
4689                 
4690                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4691
4692                 MONO_START_BB (cfg, fail_1_bb);
4693
4694                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4695                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4696
4697                 MONO_START_BB (cfg, no_proxy_bb);
4698
4699                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4700 #else
4701                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4702 #endif
4703         }
4704
4705         MONO_START_BB (cfg, ok_result_bb);
4706
4707         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4708
4709 #ifndef DISABLE_REMOTING
4710         MONO_START_BB (cfg, end_bb);
4711 #endif
4712
4713         /* FIXME: */
4714         MONO_INST_NEW (cfg, ins, OP_ICONST);
4715         ins->dreg = dreg;
4716         ins->type = STACK_I4;
4717
4718         return ins;
4719 }
4720
4721 static G_GNUC_UNUSED MonoInst*
4722 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4723 {
4724         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4725         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4726         gboolean is_i4 = TRUE;
4727
4728         switch (enum_type->type) {
4729         case MONO_TYPE_I8:
4730         case MONO_TYPE_U8:
4731 #if SIZEOF_REGISTER == 8
4732         case MONO_TYPE_I:
4733         case MONO_TYPE_U:
4734 #endif
4735                 is_i4 = FALSE;
4736                 break;
4737         }
4738
4739         {
4740                 MonoInst *load, *and, *cmp, *ceq;
4741                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4742                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4743                 int dest_reg = alloc_ireg (cfg);
4744
4745                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4746                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4747                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4748                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4749
4750                 ceq->type = STACK_I4;
4751
4752                 if (!is_i4) {
4753                         load = mono_decompose_opcode (cfg, load, NULL);
4754                         and = mono_decompose_opcode (cfg, and, NULL);
4755                         cmp = mono_decompose_opcode (cfg, cmp, NULL);
4756                         ceq = mono_decompose_opcode (cfg, ceq, NULL);
4757                 }
4758
4759                 return ceq;
4760         }
4761 }
4762
4763 /*
4764  * Returns NULL and set the cfg exception on error.
4765  */
4766 static G_GNUC_UNUSED MonoInst*
4767 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4768 {
4769         MonoInst *ptr;
4770         int dreg;
4771         gpointer trampoline;
4772         MonoInst *obj, *method_ins, *tramp_ins;
4773         MonoDomain *domain;
4774         guint8 **code_slot;
4775         
4776         // FIXME reenable optimisation for virtual case
4777         if (virtual)
4778                 return NULL;
4779
4780         if (virtual) {
4781                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4782                 g_assert (invoke);
4783
4784                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4785                         return NULL;
4786         }
4787
4788         obj = handle_alloc (cfg, klass, FALSE, 0);
4789         if (!obj)
4790                 return NULL;
4791
4792         /* Inline the contents of mono_delegate_ctor */
4793
4794         /* Set target field */
4795         /* Optimize away setting of NULL target */
4796         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4797                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4798                 if (cfg->gen_write_barriers) {
4799                         dreg = alloc_preg (cfg);
4800                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4801                         emit_write_barrier (cfg, ptr, target);
4802                 }
4803         }
4804
4805         /* Set method field */
4806         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4807         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4808
4809         /* 
4810          * To avoid looking up the compiled code belonging to the target method
4811          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4812          * store it, and we fill it after the method has been compiled.
4813          */
4814         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4815                 MonoInst *code_slot_ins;
4816
4817                 if (context_used) {
4818                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4819                 } else {
4820                         domain = mono_domain_get ();
4821                         mono_domain_lock (domain);
4822                         if (!domain_jit_info (domain)->method_code_hash)
4823                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4824                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4825                         if (!code_slot) {
4826                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4827                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4828                         }
4829                         mono_domain_unlock (domain);
4830
4831                         if (cfg->compile_aot)
4832                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4833                         else
4834                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4835                 }
4836                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4837         }
4838
4839         if (cfg->compile_aot) {
4840                 MonoDelegateClassMethodPair *del_tramp;
4841
4842                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4843                 del_tramp->klass = klass;
4844                 del_tramp->method = context_used ? NULL : method;
4845                 del_tramp->virtual = virtual;
4846                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4847         } else {
4848                 if (virtual)
4849                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4850                 else
4851                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4852                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4853         }
4854
4855         /* Set invoke_impl field */
4856         if (virtual) {
4857                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4858         } else {
4859                 dreg = alloc_preg (cfg);
4860                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4861                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4862
4863                 dreg = alloc_preg (cfg);
4864                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4865                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4866         }
4867
4868         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4869
4870         return obj;
4871 }
4872
4873 static MonoInst*
4874 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4875 {
4876         MonoJitICallInfo *info;
4877
4878         /* Need to register the icall so it gets an icall wrapper */
4879         info = mono_get_array_new_va_icall (rank);
4880
4881         cfg->flags |= MONO_CFG_HAS_VARARGS;
4882
4883         /* mono_array_new_va () needs a vararg calling convention */
4884         cfg->disable_llvm = TRUE;
4885
4886         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4887         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4888 }
4889
4890 /*
4891  * handle_constrained_gsharedvt_call:
4892  *
4893  *   Handle constrained calls where the receiver is a gsharedvt type.
4894  * Return the instruction representing the call. Set the cfg exception on failure.
4895  */
4896 static MonoInst*
4897 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_call,
4898                                                                    gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
4899 {
4900         MonoInst *ins = NULL;
4901         MonoBasicBlock *bblock = *ref_bblock;
4902         gboolean emit_widen = *ref_emit_widen;
4903
4904         /*
4905          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4906          * 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
4907          * pack the arguments into an array, and do the rest of the work in in an icall.
4908          */
4909         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4910                 (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)) &&
4911                 (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]))))) {
4912                 MonoInst *args [16];
4913
4914                 /*
4915                  * This case handles calls to
4916                  * - object:ToString()/Equals()/GetHashCode(),
4917                  * - System.IComparable<T>:CompareTo()
4918                  * - System.IEquatable<T>:Equals ()
4919                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4920                  */
4921
4922                 args [0] = sp [0];
4923                 if (mono_method_check_context_used (cmethod))
4924                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4925                 else
4926                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4927                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
4928
4929                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4930                 if (fsig->hasthis && fsig->param_count) {
4931                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4932                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4933                         ins->dreg = alloc_preg (cfg);
4934                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4935                         MONO_ADD_INS (cfg->cbb, ins);
4936                         args [4] = ins;
4937
4938                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
4939                                 int addr_reg;
4940
4941                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4942
4943                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4944                                 addr_reg = ins->dreg;
4945                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4946                         } else {
4947                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4948                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4949                         }
4950                 } else {
4951                         EMIT_NEW_ICONST (cfg, args [3], 0);
4952                         EMIT_NEW_ICONST (cfg, args [4], 0);
4953                 }
4954                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4955                 emit_widen = FALSE;
4956
4957                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
4958                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
4959                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4960                         MonoInst *add;
4961
4962                         /* Unbox */
4963                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4964                         MONO_ADD_INS (cfg->cbb, add);
4965                         /* Load value */
4966                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4967                         MONO_ADD_INS (cfg->cbb, ins);
4968                         /* ins represents the call result */
4969                 }
4970         } else {
4971                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4972         }
4973
4974         *ref_emit_widen = emit_widen;
4975         *ref_bblock = bblock;
4976
4977         return ins;
4978
4979  exception_exit:
4980         return NULL;
4981 }
4982
4983 static void
4984 mono_emit_load_got_addr (MonoCompile *cfg)
4985 {
4986         MonoInst *getaddr, *dummy_use;
4987
4988         if (!cfg->got_var || cfg->got_var_allocated)
4989                 return;
4990
4991         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4992         getaddr->cil_code = cfg->header->code;
4993         getaddr->dreg = cfg->got_var->dreg;
4994
4995         /* Add it to the start of the first bblock */
4996         if (cfg->bb_entry->code) {
4997                 getaddr->next = cfg->bb_entry->code;
4998                 cfg->bb_entry->code = getaddr;
4999         }
5000         else
5001                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5002
5003         cfg->got_var_allocated = TRUE;
5004
5005         /* 
5006          * Add a dummy use to keep the got_var alive, since real uses might
5007          * only be generated by the back ends.
5008          * Add it to end_bblock, so the variable's lifetime covers the whole
5009          * method.
5010          * It would be better to make the usage of the got var explicit in all
5011          * cases when the backend needs it (i.e. calls, throw etc.), so this
5012          * wouldn't be needed.
5013          */
5014         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5015         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5016 }
5017
5018 static int inline_limit;
5019 static gboolean inline_limit_inited;
5020
5021 static gboolean
5022 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5023 {
5024         MonoMethodHeaderSummary header;
5025         MonoVTable *vtable;
5026 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5027         MonoMethodSignature *sig = mono_method_signature (method);
5028         int i;
5029 #endif
5030
5031         if (cfg->disable_inline)
5032                 return FALSE;
5033         if (cfg->generic_sharing_context)
5034                 return FALSE;
5035
5036         if (cfg->inline_depth > 10)
5037                 return FALSE;
5038
5039 #ifdef MONO_ARCH_HAVE_LMF_OPS
5040         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5041                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5042             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5043                 return TRUE;
5044 #endif
5045
5046
5047         if (!mono_method_get_header_summary (method, &header))
5048                 return FALSE;
5049
5050         /*runtime, icall and pinvoke are checked by summary call*/
5051         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5052             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5053             (mono_class_is_marshalbyref (method->klass)) ||
5054             header.has_clauses)
5055                 return FALSE;
5056
5057         /* also consider num_locals? */
5058         /* Do the size check early to avoid creating vtables */
5059         if (!inline_limit_inited) {
5060                 if (g_getenv ("MONO_INLINELIMIT"))
5061                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5062                 else
5063                         inline_limit = INLINE_LENGTH_LIMIT;
5064                 inline_limit_inited = TRUE;
5065         }
5066         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5067                 return FALSE;
5068
5069         /*
5070          * if we can initialize the class of the method right away, we do,
5071          * otherwise we don't allow inlining if the class needs initialization,
5072          * since it would mean inserting a call to mono_runtime_class_init()
5073          * inside the inlined code
5074          */
5075         if (!(cfg->opt & MONO_OPT_SHARED)) {
5076                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5077                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5078                         vtable = mono_class_vtable (cfg->domain, method->klass);
5079                         if (!vtable)
5080                                 return FALSE;
5081                         if (!cfg->compile_aot)
5082                                 mono_runtime_class_init (vtable);
5083                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5084                         if (cfg->run_cctors && method->klass->has_cctor) {
5085                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5086                                 if (!method->klass->runtime_info)
5087                                         /* No vtable created yet */
5088                                         return FALSE;
5089                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5090                                 if (!vtable)
5091                                         return FALSE;
5092                                 /* This makes so that inline cannot trigger */
5093                                 /* .cctors: too many apps depend on them */
5094                                 /* running with a specific order... */
5095                                 if (! vtable->initialized)
5096                                         return FALSE;
5097                                 mono_runtime_class_init (vtable);
5098                         }
5099                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5100                         if (!method->klass->runtime_info)
5101                                 /* No vtable created yet */
5102                                 return FALSE;
5103                         vtable = mono_class_vtable (cfg->domain, method->klass);
5104                         if (!vtable)
5105                                 return FALSE;
5106                         if (!vtable->initialized)
5107                                 return FALSE;
5108                 }
5109         } else {
5110                 /* 
5111                  * If we're compiling for shared code
5112                  * the cctor will need to be run at aot method load time, for example,
5113                  * or at the end of the compilation of the inlining method.
5114                  */
5115                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5116                         return FALSE;
5117         }
5118
5119         /*
5120          * CAS - do not inline methods with declarative security
5121          * Note: this has to be before any possible return TRUE;
5122          */
5123         if (mono_security_method_has_declsec (method))
5124                 return FALSE;
5125
5126 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5127         if (mono_arch_is_soft_float ()) {
5128                 /* FIXME: */
5129                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5130                         return FALSE;
5131                 for (i = 0; i < sig->param_count; ++i)
5132                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5133                                 return FALSE;
5134         }
5135 #endif
5136
5137         if (g_list_find (cfg->dont_inline, method))
5138                 return FALSE;
5139
5140         return TRUE;
5141 }
5142
5143 static gboolean
5144 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5145 {
5146         if (!cfg->compile_aot) {
5147                 g_assert (vtable);
5148                 if (vtable->initialized)
5149                         return FALSE;
5150         }
5151
5152         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5153                 if (cfg->method == method)
5154                         return FALSE;
5155         }
5156
5157         if (!mono_class_needs_cctor_run (klass, method))
5158                 return FALSE;
5159
5160         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5161                 /* The initialization is already done before the method is called */
5162                 return FALSE;
5163
5164         return TRUE;
5165 }
5166
5167 static MonoInst*
5168 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5169 {
5170         MonoInst *ins;
5171         guint32 size;
5172         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5173         int context_used;
5174
5175         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5176                 size = -1;
5177         } else {
5178                 mono_class_init (klass);
5179                 size = mono_class_array_element_size (klass);
5180         }
5181
5182         mult_reg = alloc_preg (cfg);
5183         array_reg = arr->dreg;
5184         index_reg = index->dreg;
5185
5186 #if SIZEOF_REGISTER == 8
5187         /* The array reg is 64 bits but the index reg is only 32 */
5188         if (COMPILE_LLVM (cfg)) {
5189                 /* Not needed */
5190                 index2_reg = index_reg;
5191         } else {
5192                 index2_reg = alloc_preg (cfg);
5193                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5194         }
5195 #else
5196         if (index->type == STACK_I8) {
5197                 index2_reg = alloc_preg (cfg);
5198                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5199         } else {
5200                 index2_reg = index_reg;
5201         }
5202 #endif
5203
5204         if (bcheck)
5205                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5206
5207 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5208         if (size == 1 || size == 2 || size == 4 || size == 8) {
5209                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5210
5211                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5212                 ins->klass = mono_class_get_element_class (klass);
5213                 ins->type = STACK_MP;
5214
5215                 return ins;
5216         }
5217 #endif          
5218
5219         add_reg = alloc_ireg_mp (cfg);
5220
5221         if (size == -1) {
5222                 MonoInst *rgctx_ins;
5223
5224                 /* gsharedvt */
5225                 g_assert (cfg->generic_sharing_context);
5226                 context_used = mini_class_check_context_used (cfg, klass);
5227                 g_assert (context_used);
5228                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5229                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5230         } else {
5231                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5232         }
5233         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5234         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5235         ins->klass = mono_class_get_element_class (klass);
5236         ins->type = STACK_MP;
5237         MONO_ADD_INS (cfg->cbb, ins);
5238
5239         return ins;
5240 }
5241
5242 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5243 static MonoInst*
5244 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5245 {
5246         int bounds_reg = alloc_preg (cfg);
5247         int add_reg = alloc_ireg_mp (cfg);
5248         int mult_reg = alloc_preg (cfg);
5249         int mult2_reg = alloc_preg (cfg);
5250         int low1_reg = alloc_preg (cfg);
5251         int low2_reg = alloc_preg (cfg);
5252         int high1_reg = alloc_preg (cfg);
5253         int high2_reg = alloc_preg (cfg);
5254         int realidx1_reg = alloc_preg (cfg);
5255         int realidx2_reg = alloc_preg (cfg);
5256         int sum_reg = alloc_preg (cfg);
5257         int index1, index2, tmpreg;
5258         MonoInst *ins;
5259         guint32 size;
5260
5261         mono_class_init (klass);
5262         size = mono_class_array_element_size (klass);
5263
5264         index1 = index_ins1->dreg;
5265         index2 = index_ins2->dreg;
5266
5267 #if SIZEOF_REGISTER == 8
5268         /* The array reg is 64 bits but the index reg is only 32 */
5269         if (COMPILE_LLVM (cfg)) {
5270                 /* Not needed */
5271         } else {
5272                 tmpreg = alloc_preg (cfg);
5273                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5274                 index1 = tmpreg;
5275                 tmpreg = alloc_preg (cfg);
5276                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5277                 index2 = tmpreg;
5278         }
5279 #else
5280         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5281         tmpreg = -1;
5282 #endif
5283
5284         /* range checking */
5285         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5286                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5287
5288         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5289                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5290         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5291         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5292                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5293         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5294         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5295
5296         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5297                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5298         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5299         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5300                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5301         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5302         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5303
5304         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5305         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5306         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5307         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5308         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5309
5310         ins->type = STACK_MP;
5311         ins->klass = klass;
5312         MONO_ADD_INS (cfg->cbb, ins);
5313
5314         return ins;
5315 }
5316 #endif
5317
5318 static MonoInst*
5319 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5320 {
5321         int rank;
5322         MonoInst *addr;
5323         MonoMethod *addr_method;
5324         int element_size;
5325         MonoClass *eclass = cmethod->klass->element_class;
5326
5327         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5328
5329         if (rank == 1)
5330                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5331
5332 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5333         /* emit_ldelema_2 depends on OP_LMUL */
5334         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5335                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5336         }
5337 #endif
5338
5339         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5340                 element_size = 0;
5341         else
5342                 element_size = mono_class_array_element_size (eclass);
5343         addr_method = mono_marshal_get_array_address (rank, element_size);
5344         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5345
5346         return addr;
5347 }
5348
5349 static MonoBreakPolicy
5350 always_insert_breakpoint (MonoMethod *method)
5351 {
5352         return MONO_BREAK_POLICY_ALWAYS;
5353 }
5354
5355 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5356
5357 /**
5358  * mono_set_break_policy:
5359  * policy_callback: the new callback function
5360  *
5361  * Allow embedders to decide wherther to actually obey breakpoint instructions
5362  * (both break IL instructions and Debugger.Break () method calls), for example
5363  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5364  * untrusted or semi-trusted code.
5365  *
5366  * @policy_callback will be called every time a break point instruction needs to
5367  * be inserted with the method argument being the method that calls Debugger.Break()
5368  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5369  * if it wants the breakpoint to not be effective in the given method.
5370  * #MONO_BREAK_POLICY_ALWAYS is the default.
5371  */
5372 void
5373 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5374 {
5375         if (policy_callback)
5376                 break_policy_func = policy_callback;
5377         else
5378                 break_policy_func = always_insert_breakpoint;
5379 }
5380
5381 static gboolean
5382 should_insert_brekpoint (MonoMethod *method) {
5383         switch (break_policy_func (method)) {
5384         case MONO_BREAK_POLICY_ALWAYS:
5385                 return TRUE;
5386         case MONO_BREAK_POLICY_NEVER:
5387                 return FALSE;
5388         case MONO_BREAK_POLICY_ON_DBG:
5389                 g_warning ("mdb no longer supported");
5390                 return FALSE;
5391         default:
5392                 g_warning ("Incorrect value returned from break policy callback");
5393                 return FALSE;
5394         }
5395 }
5396
5397 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5398 static MonoInst*
5399 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5400 {
5401         MonoInst *addr, *store, *load;
5402         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5403
5404         /* the bounds check is already done by the callers */
5405         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5406         if (is_set) {
5407                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5408                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5409                 if (mini_type_is_reference (cfg, fsig->params [2]))
5410                         emit_write_barrier (cfg, addr, load);
5411         } else {
5412                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5413                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5414         }
5415         return store;
5416 }
5417
5418
5419 static gboolean
5420 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5421 {
5422         return mini_type_is_reference (cfg, &klass->byval_arg);
5423 }
5424
5425 static MonoInst*
5426 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5427 {
5428         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5429                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5430                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5431                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5432                 MonoInst *iargs [3];
5433
5434                 if (!helper->slot)
5435                         mono_class_setup_vtable (obj_array);
5436                 g_assert (helper->slot);
5437
5438                 if (sp [0]->type != STACK_OBJ)
5439                         return NULL;
5440                 if (sp [2]->type != STACK_OBJ)
5441                         return NULL;
5442
5443                 iargs [2] = sp [2];
5444                 iargs [1] = sp [1];
5445                 iargs [0] = sp [0];
5446
5447                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5448         } else {
5449                 MonoInst *ins;
5450
5451                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5452                         MonoInst *addr;
5453
5454                         // FIXME-VT: OP_ICONST optimization
5455                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5456                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5457                         ins->opcode = OP_STOREV_MEMBASE;
5458                 } else if (sp [1]->opcode == OP_ICONST) {
5459                         int array_reg = sp [0]->dreg;
5460                         int index_reg = sp [1]->dreg;
5461                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5462
5463                         if (safety_checks)
5464                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5465                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5466                 } else {
5467                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5468                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5469                         if (generic_class_is_reference_type (cfg, klass))
5470                                 emit_write_barrier (cfg, addr, sp [2]);
5471                 }
5472                 return ins;
5473         }
5474 }
5475
5476 static MonoInst*
5477 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5478 {
5479         MonoClass *eklass;
5480         
5481         if (is_set)
5482                 eklass = mono_class_from_mono_type (fsig->params [2]);
5483         else
5484                 eklass = mono_class_from_mono_type (fsig->ret);
5485
5486         if (is_set) {
5487                 return emit_array_store (cfg, eklass, args, FALSE);
5488         } else {
5489                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5490                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5491                 return ins;
5492         }
5493 }
5494
5495 static gboolean
5496 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5497 {
5498         uint32_t align;
5499
5500         //Only allow for valuetypes
5501         if (!param_klass->valuetype || !return_klass->valuetype)
5502                 return FALSE;
5503
5504         //That are blitable
5505         if (param_klass->has_references || return_klass->has_references)
5506                 return FALSE;
5507
5508         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5509         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5510                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5511                 return FALSE;
5512
5513         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5514                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5515                 return FALSE;
5516
5517         //And have the same size
5518         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5519                 return FALSE;
5520         return TRUE;
5521 }
5522
5523 static MonoInst*
5524 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5525 {
5526         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5527         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5528
5529         //Valuetypes that are semantically equivalent
5530         if (is_unsafe_mov_compatible (param_klass, return_klass))
5531                 return args [0];
5532
5533         //Arrays of valuetypes that are semantically equivalent
5534         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5535                 return args [0];
5536
5537         return NULL;
5538 }
5539
5540 static MonoInst*
5541 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5542 {
5543 #ifdef MONO_ARCH_SIMD_INTRINSICS
5544         MonoInst *ins = NULL;
5545
5546         if (cfg->opt & MONO_OPT_SIMD) {
5547                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5548                 if (ins)
5549                         return ins;
5550         }
5551 #endif
5552
5553         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5554 }
5555
5556 static MonoInst*
5557 emit_memory_barrier (MonoCompile *cfg, int kind)
5558 {
5559         MonoInst *ins = NULL;
5560         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5561         MONO_ADD_INS (cfg->cbb, ins);
5562         ins->backend.memory_barrier_kind = kind;
5563
5564         return ins;
5565 }
5566
5567 static MonoInst*
5568 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5569 {
5570         MonoInst *ins = NULL;
5571         int opcode = 0;
5572
5573         /* The LLVM backend supports these intrinsics */
5574         if (cmethod->klass == mono_defaults.math_class) {
5575                 if (strcmp (cmethod->name, "Sin") == 0) {
5576                         opcode = OP_SIN;
5577                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5578                         opcode = OP_COS;
5579                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5580                         opcode = OP_SQRT;
5581                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5582                         opcode = OP_ABS;
5583                 }
5584
5585                 if (opcode && fsig->param_count == 1) {
5586                         MONO_INST_NEW (cfg, ins, opcode);
5587                         ins->type = STACK_R8;
5588                         ins->dreg = mono_alloc_freg (cfg);
5589                         ins->sreg1 = args [0]->dreg;
5590                         MONO_ADD_INS (cfg->cbb, ins);
5591                 }
5592
5593                 opcode = 0;
5594                 if (cfg->opt & MONO_OPT_CMOV) {
5595                         if (strcmp (cmethod->name, "Min") == 0) {
5596                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5597                                         opcode = OP_IMIN;
5598                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5599                                         opcode = OP_IMIN_UN;
5600                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5601                                         opcode = OP_LMIN;
5602                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5603                                         opcode = OP_LMIN_UN;
5604                         } else if (strcmp (cmethod->name, "Max") == 0) {
5605                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5606                                         opcode = OP_IMAX;
5607                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5608                                         opcode = OP_IMAX_UN;
5609                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5610                                         opcode = OP_LMAX;
5611                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5612                                         opcode = OP_LMAX_UN;
5613                         }
5614                 }
5615
5616                 if (opcode && fsig->param_count == 2) {
5617                         MONO_INST_NEW (cfg, ins, opcode);
5618                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5619                         ins->dreg = mono_alloc_ireg (cfg);
5620                         ins->sreg1 = args [0]->dreg;
5621                         ins->sreg2 = args [1]->dreg;
5622                         MONO_ADD_INS (cfg->cbb, ins);
5623                 }
5624         }
5625
5626         return ins;
5627 }
5628
5629 static MonoInst*
5630 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5631 {
5632         if (cmethod->klass == mono_defaults.array_class) {
5633                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5634                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5635                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5636                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5637                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5638                         return emit_array_unsafe_mov (cfg, fsig, args);
5639         }
5640
5641         return NULL;
5642 }
5643
5644 static MonoInst*
5645 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5646 {
5647         MonoInst *ins = NULL;
5648         
5649         static MonoClass *runtime_helpers_class = NULL;
5650         if (! runtime_helpers_class)
5651                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5652                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5653
5654         if (cmethod->klass == mono_defaults.string_class) {
5655                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5656                         int dreg = alloc_ireg (cfg);
5657                         int index_reg = alloc_preg (cfg);
5658                         int mult_reg = alloc_preg (cfg);
5659                         int add_reg = alloc_preg (cfg);
5660
5661 #if SIZEOF_REGISTER == 8
5662                         /* The array reg is 64 bits but the index reg is only 32 */
5663                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5664 #else
5665                         index_reg = args [1]->dreg;
5666 #endif  
5667                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5668
5669 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5670                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5671                         add_reg = ins->dreg;
5672                         /* Avoid a warning */
5673                         mult_reg = 0;
5674                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5675                                                                    add_reg, 0);
5676 #else
5677                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5678                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5679                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5680                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5681 #endif
5682                         type_from_op (cfg, ins, NULL, NULL);
5683                         return ins;
5684                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5685                         int dreg = alloc_ireg (cfg);
5686                         /* Decompose later to allow more optimizations */
5687                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5688                         ins->type = STACK_I4;
5689                         ins->flags |= MONO_INST_FAULT;
5690                         cfg->cbb->has_array_access = TRUE;
5691                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5692
5693                         return ins;
5694                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5695                         int mult_reg = alloc_preg (cfg);
5696                         int add_reg = alloc_preg (cfg);
5697
5698                         /* The corlib functions check for oob already. */
5699                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5700                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5701                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5702                         return cfg->cbb->last_ins;
5703                 } else 
5704                         return NULL;
5705         } else if (cmethod->klass == mono_defaults.object_class) {
5706
5707                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5708                         int dreg = alloc_ireg_ref (cfg);
5709                         int vt_reg = alloc_preg (cfg);
5710                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5711                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5712                         type_from_op (cfg, ins, NULL, NULL);
5713
5714                         return ins;
5715 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5716                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5717                         int dreg = alloc_ireg (cfg);
5718                         int t1 = alloc_ireg (cfg);
5719         
5720                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5721                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5722                         ins->type = STACK_I4;
5723
5724                         return ins;
5725 #endif
5726                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5727                         MONO_INST_NEW (cfg, ins, OP_NOP);
5728                         MONO_ADD_INS (cfg->cbb, ins);
5729                         return ins;
5730                 } else
5731                         return NULL;
5732         } else if (cmethod->klass == mono_defaults.array_class) {
5733                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5734                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5735                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5736                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5737
5738 #ifndef MONO_BIG_ARRAYS
5739                 /*
5740                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5741                  * Array methods.
5742                  */
5743                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5744                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5745                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5746                         int dreg = alloc_ireg (cfg);
5747                         int bounds_reg = alloc_ireg_mp (cfg);
5748                         MonoBasicBlock *end_bb, *szarray_bb;
5749                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5750
5751                         NEW_BBLOCK (cfg, end_bb);
5752                         NEW_BBLOCK (cfg, szarray_bb);
5753
5754                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5755                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5756                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5757                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5758                         /* Non-szarray case */
5759                         if (get_length)
5760                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5761                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5762                         else
5763                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5764                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5765                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5766                         MONO_START_BB (cfg, szarray_bb);
5767                         /* Szarray case */
5768                         if (get_length)
5769                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5770                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5771                         else
5772                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5773                         MONO_START_BB (cfg, end_bb);
5774
5775                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5776                         ins->type = STACK_I4;
5777                         
5778                         return ins;
5779                 }
5780 #endif
5781
5782                 if (cmethod->name [0] != 'g')
5783                         return NULL;
5784
5785                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5786                         int dreg = alloc_ireg (cfg);
5787                         int vtable_reg = alloc_preg (cfg);
5788                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5789                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5790                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5791                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5792                         type_from_op (cfg, ins, NULL, NULL);
5793
5794                         return ins;
5795                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5796                         int dreg = alloc_ireg (cfg);
5797
5798                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5799                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5800                         type_from_op (cfg, ins, NULL, NULL);
5801
5802                         return ins;
5803                 } else
5804                         return NULL;
5805         } else if (cmethod->klass == runtime_helpers_class) {
5806
5807                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5808                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5809                         return ins;
5810                 } else
5811                         return NULL;
5812         } else if (cmethod->klass == mono_defaults.thread_class) {
5813                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5814                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5815                         MONO_ADD_INS (cfg->cbb, ins);
5816                         return ins;
5817                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5818                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5819                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5820                         guint32 opcode = 0;
5821                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5822
5823                         if (fsig->params [0]->type == MONO_TYPE_I1)
5824                                 opcode = OP_LOADI1_MEMBASE;
5825                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5826                                 opcode = OP_LOADU1_MEMBASE;
5827                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5828                                 opcode = OP_LOADI2_MEMBASE;
5829                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5830                                 opcode = OP_LOADU2_MEMBASE;
5831                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5832                                 opcode = OP_LOADI4_MEMBASE;
5833                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5834                                 opcode = OP_LOADU4_MEMBASE;
5835                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5836                                 opcode = OP_LOADI8_MEMBASE;
5837                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5838                                 opcode = OP_LOADR4_MEMBASE;
5839                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5840                                 opcode = OP_LOADR8_MEMBASE;
5841                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5842                                 opcode = OP_LOAD_MEMBASE;
5843
5844                         if (opcode) {
5845                                 MONO_INST_NEW (cfg, ins, opcode);
5846                                 ins->inst_basereg = args [0]->dreg;
5847                                 ins->inst_offset = 0;
5848                                 MONO_ADD_INS (cfg->cbb, ins);
5849
5850                                 switch (fsig->params [0]->type) {
5851                                 case MONO_TYPE_I1:
5852                                 case MONO_TYPE_U1:
5853                                 case MONO_TYPE_I2:
5854                                 case MONO_TYPE_U2:
5855                                 case MONO_TYPE_I4:
5856                                 case MONO_TYPE_U4:
5857                                         ins->dreg = mono_alloc_ireg (cfg);
5858                                         ins->type = STACK_I4;
5859                                         break;
5860                                 case MONO_TYPE_I8:
5861                                 case MONO_TYPE_U8:
5862                                         ins->dreg = mono_alloc_lreg (cfg);
5863                                         ins->type = STACK_I8;
5864                                         break;
5865                                 case MONO_TYPE_I:
5866                                 case MONO_TYPE_U:
5867                                         ins->dreg = mono_alloc_ireg (cfg);
5868 #if SIZEOF_REGISTER == 8
5869                                         ins->type = STACK_I8;
5870 #else
5871                                         ins->type = STACK_I4;
5872 #endif
5873                                         break;
5874                                 case MONO_TYPE_R4:
5875                                 case MONO_TYPE_R8:
5876                                         ins->dreg = mono_alloc_freg (cfg);
5877                                         ins->type = STACK_R8;
5878                                         break;
5879                                 default:
5880                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5881                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5882                                         ins->type = STACK_OBJ;
5883                                         break;
5884                                 }
5885
5886                                 if (opcode == OP_LOADI8_MEMBASE)
5887                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5888
5889                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5890
5891                                 return ins;
5892                         }
5893                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5894                         guint32 opcode = 0;
5895                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5896
5897                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5898                                 opcode = OP_STOREI1_MEMBASE_REG;
5899                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5900                                 opcode = OP_STOREI2_MEMBASE_REG;
5901                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5902                                 opcode = OP_STOREI4_MEMBASE_REG;
5903                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5904                                 opcode = OP_STOREI8_MEMBASE_REG;
5905                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5906                                 opcode = OP_STORER4_MEMBASE_REG;
5907                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5908                                 opcode = OP_STORER8_MEMBASE_REG;
5909                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5910                                 opcode = OP_STORE_MEMBASE_REG;
5911
5912                         if (opcode) {
5913                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5914
5915                                 MONO_INST_NEW (cfg, ins, opcode);
5916                                 ins->sreg1 = args [1]->dreg;
5917                                 ins->inst_destbasereg = args [0]->dreg;
5918                                 ins->inst_offset = 0;
5919                                 MONO_ADD_INS (cfg->cbb, ins);
5920
5921                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5922                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5923
5924                                 return ins;
5925                         }
5926                 }
5927         } else if (cmethod->klass == mono_defaults.monitor_class) {
5928 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5929                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5930                         MonoCallInst *call;
5931
5932                         if (COMPILE_LLVM (cfg)) {
5933                                 /* 
5934                                  * Pass the argument normally, the LLVM backend will handle the
5935                                  * calling convention problems.
5936                                  */
5937                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5938                         } else {
5939                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5940                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5941                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5942                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5943                         }
5944
5945                         return (MonoInst*)call;
5946 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5947                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5948                         MonoCallInst *call;
5949
5950                         if (COMPILE_LLVM (cfg)) {
5951                                 /*
5952                                  * Pass the argument normally, the LLVM backend will handle the
5953                                  * calling convention problems.
5954                                  */
5955                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5956                         } else {
5957                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5958                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5959                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5960                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5961                         }
5962
5963                         return (MonoInst*)call;
5964 #endif
5965                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
5966                         MonoCallInst *call;
5967
5968                         if (COMPILE_LLVM (cfg)) {
5969                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5970                         } else {
5971                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5972                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5973                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5974                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5975                         }
5976
5977                         return (MonoInst*)call;
5978                 }
5979 #endif
5980         } else if (cmethod->klass->image == mono_defaults.corlib &&
5981                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5982                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5983                 ins = NULL;
5984
5985 #if SIZEOF_REGISTER == 8
5986                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5987                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5988                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5989                                 ins->dreg = mono_alloc_preg (cfg);
5990                                 ins->sreg1 = args [0]->dreg;
5991                                 ins->type = STACK_I8;
5992                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5993                                 MONO_ADD_INS (cfg->cbb, ins);
5994                         } else {
5995                                 MonoInst *load_ins;
5996
5997                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5998
5999                                 /* 64 bit reads are already atomic */
6000                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6001                                 load_ins->dreg = mono_alloc_preg (cfg);
6002                                 load_ins->inst_basereg = args [0]->dreg;
6003                                 load_ins->inst_offset = 0;
6004                                 load_ins->type = STACK_I8;
6005                                 MONO_ADD_INS (cfg->cbb, load_ins);
6006
6007                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6008
6009                                 ins = load_ins;
6010                         }
6011                 }
6012 #endif
6013
6014                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6015                         MonoInst *ins_iconst;
6016                         guint32 opcode = 0;
6017
6018                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6019                                 opcode = OP_ATOMIC_ADD_I4;
6020                                 cfg->has_atomic_add_i4 = TRUE;
6021                         }
6022 #if SIZEOF_REGISTER == 8
6023                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6024                                 opcode = OP_ATOMIC_ADD_I8;
6025 #endif
6026                         if (opcode) {
6027                                 if (!mono_arch_opcode_supported (opcode))
6028                                         return NULL;
6029                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6030                                 ins_iconst->inst_c0 = 1;
6031                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6032                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6033
6034                                 MONO_INST_NEW (cfg, ins, opcode);
6035                                 ins->dreg = mono_alloc_ireg (cfg);
6036                                 ins->inst_basereg = args [0]->dreg;
6037                                 ins->inst_offset = 0;
6038                                 ins->sreg2 = ins_iconst->dreg;
6039                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6040                                 MONO_ADD_INS (cfg->cbb, ins);
6041                         }
6042                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6043                         MonoInst *ins_iconst;
6044                         guint32 opcode = 0;
6045
6046                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6047                                 opcode = OP_ATOMIC_ADD_I4;
6048                                 cfg->has_atomic_add_i4 = TRUE;
6049                         }
6050 #if SIZEOF_REGISTER == 8
6051                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6052                                 opcode = OP_ATOMIC_ADD_I8;
6053 #endif
6054                         if (opcode) {
6055                                 if (!mono_arch_opcode_supported (opcode))
6056                                         return NULL;
6057                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6058                                 ins_iconst->inst_c0 = -1;
6059                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6060                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6061
6062                                 MONO_INST_NEW (cfg, ins, opcode);
6063                                 ins->dreg = mono_alloc_ireg (cfg);
6064                                 ins->inst_basereg = args [0]->dreg;
6065                                 ins->inst_offset = 0;
6066                                 ins->sreg2 = ins_iconst->dreg;
6067                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6068                                 MONO_ADD_INS (cfg->cbb, ins);
6069                         }
6070                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6071                         guint32 opcode = 0;
6072
6073                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6074                                 opcode = OP_ATOMIC_ADD_I4;
6075                                 cfg->has_atomic_add_i4 = TRUE;
6076                         }
6077 #if SIZEOF_REGISTER == 8
6078                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6079                                 opcode = OP_ATOMIC_ADD_I8;
6080 #endif
6081                         if (opcode) {
6082                                 if (!mono_arch_opcode_supported (opcode))
6083                                         return NULL;
6084                                 MONO_INST_NEW (cfg, ins, opcode);
6085                                 ins->dreg = mono_alloc_ireg (cfg);
6086                                 ins->inst_basereg = args [0]->dreg;
6087                                 ins->inst_offset = 0;
6088                                 ins->sreg2 = args [1]->dreg;
6089                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6090                                 MONO_ADD_INS (cfg->cbb, ins);
6091                         }
6092                 }
6093                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6094                         MonoInst *f2i = NULL, *i2f;
6095                         guint32 opcode, f2i_opcode, i2f_opcode;
6096                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6097                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6098
6099                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6100                             fsig->params [0]->type == MONO_TYPE_R4) {
6101                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6102                                 f2i_opcode = OP_MOVE_F_TO_I4;
6103                                 i2f_opcode = OP_MOVE_I4_TO_F;
6104                                 cfg->has_atomic_exchange_i4 = TRUE;
6105                         }
6106 #if SIZEOF_REGISTER == 8
6107                         else if (is_ref ||
6108                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6109                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6110                                  fsig->params [0]->type == MONO_TYPE_I) {
6111                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6112                                 f2i_opcode = OP_MOVE_F_TO_I8;
6113                                 i2f_opcode = OP_MOVE_I8_TO_F;
6114                         }
6115 #else
6116                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6117                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6118                                 cfg->has_atomic_exchange_i4 = TRUE;
6119                         }
6120 #endif
6121                         else
6122                                 return NULL;
6123
6124                         if (!mono_arch_opcode_supported (opcode))
6125                                 return NULL;
6126
6127                         if (is_float) {
6128                                 /* TODO: Decompose these opcodes instead of bailing here. */
6129                                 if (COMPILE_SOFT_FLOAT (cfg))
6130                                         return NULL;
6131
6132                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6133                                 f2i->dreg = mono_alloc_ireg (cfg);
6134                                 f2i->sreg1 = args [1]->dreg;
6135                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6136                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6137                                 MONO_ADD_INS (cfg->cbb, f2i);
6138                         }
6139
6140                         MONO_INST_NEW (cfg, ins, opcode);
6141                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6142                         ins->inst_basereg = args [0]->dreg;
6143                         ins->inst_offset = 0;
6144                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6145                         MONO_ADD_INS (cfg->cbb, ins);
6146
6147                         switch (fsig->params [0]->type) {
6148                         case MONO_TYPE_I4:
6149                                 ins->type = STACK_I4;
6150                                 break;
6151                         case MONO_TYPE_I8:
6152                                 ins->type = STACK_I8;
6153                                 break;
6154                         case MONO_TYPE_I:
6155 #if SIZEOF_REGISTER == 8
6156                                 ins->type = STACK_I8;
6157 #else
6158                                 ins->type = STACK_I4;
6159 #endif
6160                                 break;
6161                         case MONO_TYPE_R4:
6162                         case MONO_TYPE_R8:
6163                                 ins->type = STACK_R8;
6164                                 break;
6165                         default:
6166                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6167                                 ins->type = STACK_OBJ;
6168                                 break;
6169                         }
6170
6171                         if (is_float) {
6172                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6173                                 i2f->dreg = mono_alloc_freg (cfg);
6174                                 i2f->sreg1 = ins->dreg;
6175                                 i2f->type = STACK_R8;
6176                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6177                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6178                                 MONO_ADD_INS (cfg->cbb, i2f);
6179
6180                                 ins = i2f;
6181                         }
6182
6183                         if (cfg->gen_write_barriers && is_ref)
6184                                 emit_write_barrier (cfg, args [0], args [1]);
6185                 }
6186                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6187                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6188                         guint32 opcode, f2i_opcode, i2f_opcode;
6189                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6190                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6191
6192                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6193                             fsig->params [1]->type == MONO_TYPE_R4) {
6194                                 opcode = OP_ATOMIC_CAS_I4;
6195                                 f2i_opcode = OP_MOVE_F_TO_I4;
6196                                 i2f_opcode = OP_MOVE_I4_TO_F;
6197                                 cfg->has_atomic_cas_i4 = TRUE;
6198                         }
6199 #if SIZEOF_REGISTER == 8
6200                         else if (is_ref ||
6201                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6202                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6203                                  fsig->params [1]->type == MONO_TYPE_I) {
6204                                 opcode = OP_ATOMIC_CAS_I8;
6205                                 f2i_opcode = OP_MOVE_F_TO_I8;
6206                                 i2f_opcode = OP_MOVE_I8_TO_F;
6207                         }
6208 #else
6209                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6210                                 opcode = OP_ATOMIC_CAS_I4;
6211                                 cfg->has_atomic_cas_i4 = TRUE;
6212                         }
6213 #endif
6214                         else
6215                                 return NULL;
6216
6217                         if (!mono_arch_opcode_supported (opcode))
6218                                 return NULL;
6219
6220                         if (is_float) {
6221                                 /* TODO: Decompose these opcodes instead of bailing here. */
6222                                 if (COMPILE_SOFT_FLOAT (cfg))
6223                                         return NULL;
6224
6225                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6226                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6227                                 f2i_new->sreg1 = args [1]->dreg;
6228                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6229                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6230                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6231
6232                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6233                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6234                                 f2i_cmp->sreg1 = args [2]->dreg;
6235                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6236                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6237                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6238                         }
6239
6240                         MONO_INST_NEW (cfg, ins, opcode);
6241                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6242                         ins->sreg1 = args [0]->dreg;
6243                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6244                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6245                         MONO_ADD_INS (cfg->cbb, ins);
6246
6247                         switch (fsig->params [1]->type) {
6248                         case MONO_TYPE_I4:
6249                                 ins->type = STACK_I4;
6250                                 break;
6251                         case MONO_TYPE_I8:
6252                                 ins->type = STACK_I8;
6253                                 break;
6254                         case MONO_TYPE_I:
6255 #if SIZEOF_REGISTER == 8
6256                                 ins->type = STACK_I8;
6257 #else
6258                                 ins->type = STACK_I4;
6259 #endif
6260                                 break;
6261                         case MONO_TYPE_R4:
6262                         case MONO_TYPE_R8:
6263                                 ins->type = STACK_R8;
6264                                 break;
6265                         default:
6266                                 g_assert (mini_type_is_reference (cfg, fsig->params [1]));
6267                                 ins->type = STACK_OBJ;
6268                                 break;
6269                         }
6270
6271                         if (is_float) {
6272                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6273                                 i2f->dreg = mono_alloc_freg (cfg);
6274                                 i2f->sreg1 = ins->dreg;
6275                                 i2f->type = STACK_R8;
6276                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6277                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6278                                 MONO_ADD_INS (cfg->cbb, i2f);
6279
6280                                 ins = i2f;
6281                         }
6282
6283                         if (cfg->gen_write_barriers && is_ref)
6284                                 emit_write_barrier (cfg, args [0], args [1]);
6285                 }
6286                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6287                          fsig->params [1]->type == MONO_TYPE_I4) {
6288                         MonoInst *cmp, *ceq;
6289
6290                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6291                                 return NULL;
6292
6293                         /* int32 r = CAS (location, value, comparand); */
6294                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6295                         ins->dreg = alloc_ireg (cfg);
6296                         ins->sreg1 = args [0]->dreg;
6297                         ins->sreg2 = args [1]->dreg;
6298                         ins->sreg3 = args [2]->dreg;
6299                         ins->type = STACK_I4;
6300                         MONO_ADD_INS (cfg->cbb, ins);
6301
6302                         /* bool result = r == comparand; */
6303                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6304                         cmp->sreg1 = ins->dreg;
6305                         cmp->sreg2 = args [2]->dreg;
6306                         cmp->type = STACK_I4;
6307                         MONO_ADD_INS (cfg->cbb, cmp);
6308
6309                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6310                         ceq->dreg = alloc_ireg (cfg);
6311                         ceq->type = STACK_I4;
6312                         MONO_ADD_INS (cfg->cbb, ceq);
6313
6314                         /* *success = result; */
6315                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6316
6317                         cfg->has_atomic_cas_i4 = TRUE;
6318                 }
6319                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6320                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6321
6322                 if (ins)
6323                         return ins;
6324         } else if (cmethod->klass->image == mono_defaults.corlib &&
6325                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6326                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6327                 ins = NULL;
6328
6329                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6330                         guint32 opcode = 0;
6331                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6332                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6333
6334                         if (fsig->params [0]->type == MONO_TYPE_I1)
6335                                 opcode = OP_ATOMIC_LOAD_I1;
6336                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6337                                 opcode = OP_ATOMIC_LOAD_U1;
6338                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6339                                 opcode = OP_ATOMIC_LOAD_I2;
6340                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6341                                 opcode = OP_ATOMIC_LOAD_U2;
6342                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6343                                 opcode = OP_ATOMIC_LOAD_I4;
6344                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6345                                 opcode = OP_ATOMIC_LOAD_U4;
6346                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6347                                 opcode = OP_ATOMIC_LOAD_R4;
6348                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6349                                 opcode = OP_ATOMIC_LOAD_R8;
6350 #if SIZEOF_REGISTER == 8
6351                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6352                                 opcode = OP_ATOMIC_LOAD_I8;
6353                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6354                                 opcode = OP_ATOMIC_LOAD_U8;
6355 #else
6356                         else if (fsig->params [0]->type == MONO_TYPE_I)
6357                                 opcode = OP_ATOMIC_LOAD_I4;
6358                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6359                                 opcode = OP_ATOMIC_LOAD_U4;
6360 #endif
6361
6362                         if (opcode) {
6363                                 if (!mono_arch_opcode_supported (opcode))
6364                                         return NULL;
6365
6366                                 MONO_INST_NEW (cfg, ins, opcode);
6367                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6368                                 ins->sreg1 = args [0]->dreg;
6369                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6370                                 MONO_ADD_INS (cfg->cbb, ins);
6371
6372                                 switch (fsig->params [0]->type) {
6373                                 case MONO_TYPE_BOOLEAN:
6374                                 case MONO_TYPE_I1:
6375                                 case MONO_TYPE_U1:
6376                                 case MONO_TYPE_I2:
6377                                 case MONO_TYPE_U2:
6378                                 case MONO_TYPE_I4:
6379                                 case MONO_TYPE_U4:
6380                                         ins->type = STACK_I4;
6381                                         break;
6382                                 case MONO_TYPE_I8:
6383                                 case MONO_TYPE_U8:
6384                                         ins->type = STACK_I8;
6385                                         break;
6386                                 case MONO_TYPE_I:
6387                                 case MONO_TYPE_U:
6388 #if SIZEOF_REGISTER == 8
6389                                         ins->type = STACK_I8;
6390 #else
6391                                         ins->type = STACK_I4;
6392 #endif
6393                                         break;
6394                                 case MONO_TYPE_R4:
6395                                 case MONO_TYPE_R8:
6396                                         ins->type = STACK_R8;
6397                                         break;
6398                                 default:
6399                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6400                                         ins->type = STACK_OBJ;
6401                                         break;
6402                                 }
6403                         }
6404                 }
6405
6406                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6407                         guint32 opcode = 0;
6408                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6409
6410                         if (fsig->params [0]->type == MONO_TYPE_I1)
6411                                 opcode = OP_ATOMIC_STORE_I1;
6412                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6413                                 opcode = OP_ATOMIC_STORE_U1;
6414                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6415                                 opcode = OP_ATOMIC_STORE_I2;
6416                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6417                                 opcode = OP_ATOMIC_STORE_U2;
6418                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6419                                 opcode = OP_ATOMIC_STORE_I4;
6420                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6421                                 opcode = OP_ATOMIC_STORE_U4;
6422                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6423                                 opcode = OP_ATOMIC_STORE_R4;
6424                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6425                                 opcode = OP_ATOMIC_STORE_R8;
6426 #if SIZEOF_REGISTER == 8
6427                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6428                                 opcode = OP_ATOMIC_STORE_I8;
6429                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6430                                 opcode = OP_ATOMIC_STORE_U8;
6431 #else
6432                         else if (fsig->params [0]->type == MONO_TYPE_I)
6433                                 opcode = OP_ATOMIC_STORE_I4;
6434                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6435                                 opcode = OP_ATOMIC_STORE_U4;
6436 #endif
6437
6438                         if (opcode) {
6439                                 if (!mono_arch_opcode_supported (opcode))
6440                                         return NULL;
6441
6442                                 MONO_INST_NEW (cfg, ins, opcode);
6443                                 ins->dreg = args [0]->dreg;
6444                                 ins->sreg1 = args [1]->dreg;
6445                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6446                                 MONO_ADD_INS (cfg->cbb, ins);
6447
6448                                 if (cfg->gen_write_barriers && is_ref)
6449                                         emit_write_barrier (cfg, args [0], args [1]);
6450                         }
6451                 }
6452
6453                 if (ins)
6454                         return ins;
6455         } else if (cmethod->klass->image == mono_defaults.corlib &&
6456                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6457                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6458                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6459                         if (should_insert_brekpoint (cfg->method)) {
6460                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6461                         } else {
6462                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6463                                 MONO_ADD_INS (cfg->cbb, ins);
6464                         }
6465                         return ins;
6466                 }
6467         } else if (cmethod->klass->image == mono_defaults.corlib &&
6468                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6469                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6470                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6471 #ifdef TARGET_WIN32
6472                         EMIT_NEW_ICONST (cfg, ins, 1);
6473 #else
6474                         EMIT_NEW_ICONST (cfg, ins, 0);
6475 #endif
6476                 }
6477         } else if (cmethod->klass == mono_defaults.math_class) {
6478                 /* 
6479                  * There is general branchless code for Min/Max, but it does not work for 
6480                  * all inputs:
6481                  * http://everything2.com/?node_id=1051618
6482                  */
6483         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6484                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6485                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6486                    !strcmp (cmethod->klass->name, "Selector")) {
6487 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6488                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6489                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6490                     cfg->compile_aot) {
6491                         MonoInst *pi;
6492                         MonoJumpInfoToken *ji;
6493                         MonoString *s;
6494
6495                         cfg->disable_llvm = TRUE;
6496
6497                         if (args [0]->opcode == OP_GOT_ENTRY) {
6498                                 pi = args [0]->inst_p1;
6499                                 g_assert (pi->opcode == OP_PATCH_INFO);
6500                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6501                                 ji = pi->inst_p0;
6502                         } else {
6503                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6504                                 ji = args [0]->inst_p0;
6505                         }
6506
6507                         NULLIFY_INS (args [0]);
6508
6509                         // FIXME: Ugly
6510                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6511                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6512                         ins->dreg = mono_alloc_ireg (cfg);
6513                         // FIXME: Leaks
6514                         ins->inst_p0 = mono_string_to_utf8 (s);
6515                         MONO_ADD_INS (cfg->cbb, ins);
6516                         return ins;
6517                 }
6518 #endif
6519         }
6520
6521 #ifdef MONO_ARCH_SIMD_INTRINSICS
6522         if (cfg->opt & MONO_OPT_SIMD) {
6523                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6524                 if (ins)
6525                         return ins;
6526         }
6527 #endif
6528
6529         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6530         if (ins)
6531                 return ins;
6532
6533         if (COMPILE_LLVM (cfg)) {
6534                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6535                 if (ins)
6536                         return ins;
6537         }
6538
6539         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6540 }
6541
6542 /*
6543  * This entry point could be used later for arbitrary method
6544  * redirection.
6545  */
6546 inline static MonoInst*
6547 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6548                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6549 {
6550         if (method->klass == mono_defaults.string_class) {
6551                 /* managed string allocation support */
6552                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6553                         MonoInst *iargs [2];
6554                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6555                         MonoMethod *managed_alloc = NULL;
6556
6557                         g_assert (vtable); /*Should not fail since it System.String*/
6558 #ifndef MONO_CROSS_COMPILE
6559                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6560 #endif
6561                         if (!managed_alloc)
6562                                 return NULL;
6563                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6564                         iargs [1] = args [0];
6565                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6566                 }
6567         }
6568         return NULL;
6569 }
6570
6571 static void
6572 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6573 {
6574         MonoInst *store, *temp;
6575         int i;
6576
6577         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6578                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6579
6580                 /*
6581                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6582                  * would be different than the MonoInst's used to represent arguments, and
6583                  * the ldelema implementation can't deal with that.
6584                  * Solution: When ldelema is used on an inline argument, create a var for 
6585                  * it, emit ldelema on that var, and emit the saving code below in
6586                  * inline_method () if needed.
6587                  */
6588                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6589                 cfg->args [i] = temp;
6590                 /* This uses cfg->args [i] which is set by the preceeding line */
6591                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6592                 store->cil_code = sp [0]->cil_code;
6593                 sp++;
6594         }
6595 }
6596
6597 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6598 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6599
6600 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6601 static gboolean
6602 check_inline_called_method_name_limit (MonoMethod *called_method)
6603 {
6604         int strncmp_result;
6605         static const char *limit = NULL;
6606         
6607         if (limit == NULL) {
6608                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6609
6610                 if (limit_string != NULL)
6611                         limit = limit_string;
6612                 else
6613                         limit = "";
6614         }
6615
6616         if (limit [0] != '\0') {
6617                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6618
6619                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6620                 g_free (called_method_name);
6621         
6622                 //return (strncmp_result <= 0);
6623                 return (strncmp_result == 0);
6624         } else {
6625                 return TRUE;
6626         }
6627 }
6628 #endif
6629
6630 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6631 static gboolean
6632 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6633 {
6634         int strncmp_result;
6635         static const char *limit = NULL;
6636         
6637         if (limit == NULL) {
6638                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6639                 if (limit_string != NULL) {
6640                         limit = limit_string;
6641                 } else {
6642                         limit = "";
6643                 }
6644         }
6645
6646         if (limit [0] != '\0') {
6647                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6648
6649                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6650                 g_free (caller_method_name);
6651         
6652                 //return (strncmp_result <= 0);
6653                 return (strncmp_result == 0);
6654         } else {
6655                 return TRUE;
6656         }
6657 }
6658 #endif
6659
6660 static void
6661 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6662 {
6663         static double r8_0 = 0.0;
6664         static float r4_0 = 0.0;
6665         MonoInst *ins;
6666         int t;
6667
6668         rtype = mini_get_underlying_type (cfg, rtype);
6669         t = rtype->type;
6670
6671         if (rtype->byref) {
6672                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6673         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6674                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6675         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6676                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6677         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6678                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6679                 ins->type = STACK_R4;
6680                 ins->inst_p0 = (void*)&r4_0;
6681                 ins->dreg = dreg;
6682                 MONO_ADD_INS (cfg->cbb, ins);
6683         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6684                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6685                 ins->type = STACK_R8;
6686                 ins->inst_p0 = (void*)&r8_0;
6687                 ins->dreg = dreg;
6688                 MONO_ADD_INS (cfg->cbb, ins);
6689         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6690                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6691                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6692         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6693                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6694         } else {
6695                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6696         }
6697 }
6698
6699 static void
6700 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6701 {
6702         int t;
6703
6704         rtype = mini_get_underlying_type (cfg, rtype);
6705         t = rtype->type;
6706
6707         if (rtype->byref) {
6708                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6709         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6710                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6711         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6712                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6713         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6714                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6715         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6716                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6717         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6718                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6719                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6720         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6721                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6722         } else {
6723                 emit_init_rvar (cfg, dreg, rtype);
6724         }
6725 }
6726
6727 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6728 static void
6729 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6730 {
6731         MonoInst *var = cfg->locals [local];
6732         if (COMPILE_SOFT_FLOAT (cfg)) {
6733                 MonoInst *store;
6734                 int reg = alloc_dreg (cfg, var->type);
6735                 emit_init_rvar (cfg, reg, type);
6736                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6737         } else {
6738                 if (init)
6739                         emit_init_rvar (cfg, var->dreg, type);
6740                 else
6741                         emit_dummy_init_rvar (cfg, var->dreg, type);
6742         }
6743 }
6744
6745 /*
6746  * inline_method:
6747  *
6748  *   Return the cost of inlining CMETHOD.
6749  */
6750 static int
6751 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6752                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6753 {
6754         MonoInst *ins, *rvar = NULL;
6755         MonoMethodHeader *cheader;
6756         MonoBasicBlock *ebblock, *sbblock;
6757         int i, costs;
6758         MonoMethod *prev_inlined_method;
6759         MonoInst **prev_locals, **prev_args;
6760         MonoType **prev_arg_types;
6761         guint prev_real_offset;
6762         GHashTable *prev_cbb_hash;
6763         MonoBasicBlock **prev_cil_offset_to_bb;
6764         MonoBasicBlock *prev_cbb;
6765         unsigned char* prev_cil_start;
6766         guint32 prev_cil_offset_to_bb_len;
6767         MonoMethod *prev_current_method;
6768         MonoGenericContext *prev_generic_context;
6769         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6770
6771         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6772
6773 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6774         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6775                 return 0;
6776 #endif
6777 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6778         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6779                 return 0;
6780 #endif
6781
6782         if (!fsig)
6783                 fsig = mono_method_signature (cmethod);
6784
6785         if (cfg->verbose_level > 2)
6786                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6787
6788         if (!cmethod->inline_info) {
6789                 cfg->stat_inlineable_methods++;
6790                 cmethod->inline_info = 1;
6791         }
6792
6793         /* allocate local variables */
6794         cheader = mono_method_get_header (cmethod);
6795
6796         if (cheader == NULL || mono_loader_get_last_error ()) {
6797                 MonoLoaderError *error = mono_loader_get_last_error ();
6798
6799                 if (cheader)
6800                         mono_metadata_free_mh (cheader);
6801                 if (inline_always && error)
6802                         mono_cfg_set_exception (cfg, error->exception_type);
6803
6804                 mono_loader_clear_error ();
6805                 return 0;
6806         }
6807
6808         /*Must verify before creating locals as it can cause the JIT to assert.*/
6809         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6810                 mono_metadata_free_mh (cheader);
6811                 return 0;
6812         }
6813
6814         /* allocate space to store the return value */
6815         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6816                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6817         }
6818
6819         prev_locals = cfg->locals;
6820         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6821         for (i = 0; i < cheader->num_locals; ++i)
6822                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6823
6824         /* allocate start and end blocks */
6825         /* This is needed so if the inline is aborted, we can clean up */
6826         NEW_BBLOCK (cfg, sbblock);
6827         sbblock->real_offset = real_offset;
6828
6829         NEW_BBLOCK (cfg, ebblock);
6830         ebblock->block_num = cfg->num_bblocks++;
6831         ebblock->real_offset = real_offset;
6832
6833         prev_args = cfg->args;
6834         prev_arg_types = cfg->arg_types;
6835         prev_inlined_method = cfg->inlined_method;
6836         cfg->inlined_method = cmethod;
6837         cfg->ret_var_set = FALSE;
6838         cfg->inline_depth ++;
6839         prev_real_offset = cfg->real_offset;
6840         prev_cbb_hash = cfg->cbb_hash;
6841         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6842         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6843         prev_cil_start = cfg->cil_start;
6844         prev_cbb = cfg->cbb;
6845         prev_current_method = cfg->current_method;
6846         prev_generic_context = cfg->generic_context;
6847         prev_ret_var_set = cfg->ret_var_set;
6848         prev_disable_inline = cfg->disable_inline;
6849
6850         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6851                 virtual = TRUE;
6852
6853         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6854
6855         ret_var_set = cfg->ret_var_set;
6856
6857         cfg->inlined_method = prev_inlined_method;
6858         cfg->real_offset = prev_real_offset;
6859         cfg->cbb_hash = prev_cbb_hash;
6860         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6861         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6862         cfg->cil_start = prev_cil_start;
6863         cfg->locals = prev_locals;
6864         cfg->args = prev_args;
6865         cfg->arg_types = prev_arg_types;
6866         cfg->current_method = prev_current_method;
6867         cfg->generic_context = prev_generic_context;
6868         cfg->ret_var_set = prev_ret_var_set;
6869         cfg->disable_inline = prev_disable_inline;
6870         cfg->inline_depth --;
6871
6872         if ((costs >= 0 && costs < 60) || inline_always) {
6873                 if (cfg->verbose_level > 2)
6874                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6875                 
6876                 cfg->stat_inlined_methods++;
6877
6878                 /* always add some code to avoid block split failures */
6879                 MONO_INST_NEW (cfg, ins, OP_NOP);
6880                 MONO_ADD_INS (prev_cbb, ins);
6881
6882                 prev_cbb->next_bb = sbblock;
6883                 link_bblock (cfg, prev_cbb, sbblock);
6884
6885                 /* 
6886                  * Get rid of the begin and end bblocks if possible to aid local
6887                  * optimizations.
6888                  */
6889                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6890
6891                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6892                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6893
6894                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6895                         MonoBasicBlock *prev = ebblock->in_bb [0];
6896                         mono_merge_basic_blocks (cfg, prev, ebblock);
6897                         cfg->cbb = prev;
6898                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6899                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6900                                 cfg->cbb = prev_cbb;
6901                         }
6902                 } else {
6903                         /* 
6904                          * Its possible that the rvar is set in some prev bblock, but not in others.
6905                          * (#1835).
6906                          */
6907                         if (rvar) {
6908                                 MonoBasicBlock *bb;
6909
6910                                 for (i = 0; i < ebblock->in_count; ++i) {
6911                                         bb = ebblock->in_bb [i];
6912
6913                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6914                                                 cfg->cbb = bb;
6915
6916                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6917                                         }
6918                                 }
6919                         }
6920
6921                         cfg->cbb = ebblock;
6922                 }
6923
6924                 if (out_cbb)
6925                         *out_cbb = cfg->cbb;
6926
6927                 if (rvar) {
6928                         /*
6929                          * If the inlined method contains only a throw, then the ret var is not 
6930                          * set, so set it to a dummy value.
6931                          */
6932                         if (!ret_var_set)
6933                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6934
6935                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6936                         *sp++ = ins;
6937                 }
6938                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6939                 return costs + 1;
6940         } else {
6941                 if (cfg->verbose_level > 2)
6942                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6943                 cfg->exception_type = MONO_EXCEPTION_NONE;
6944                 mono_loader_clear_error ();
6945
6946                 /* This gets rid of the newly added bblocks */
6947                 cfg->cbb = prev_cbb;
6948         }
6949         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6950         return 0;
6951 }
6952
6953 /*
6954  * Some of these comments may well be out-of-date.
6955  * Design decisions: we do a single pass over the IL code (and we do bblock 
6956  * splitting/merging in the few cases when it's required: a back jump to an IL
6957  * address that was not already seen as bblock starting point).
6958  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6959  * Complex operations are decomposed in simpler ones right away. We need to let the 
6960  * arch-specific code peek and poke inside this process somehow (except when the 
6961  * optimizations can take advantage of the full semantic info of coarse opcodes).
6962  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6963  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6964  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6965  * opcode with value bigger than OP_LAST.
6966  * At this point the IR can be handed over to an interpreter, a dumb code generator
6967  * or to the optimizing code generator that will translate it to SSA form.
6968  *
6969  * Profiling directed optimizations.
6970  * We may compile by default with few or no optimizations and instrument the code
6971  * or the user may indicate what methods to optimize the most either in a config file
6972  * or through repeated runs where the compiler applies offline the optimizations to 
6973  * each method and then decides if it was worth it.
6974  */
6975
6976 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6977 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6978 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6979 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6980 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6981 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6982 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6983 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6984
6985 /* offset from br.s -> br like opcodes */
6986 #define BIG_BRANCH_OFFSET 13
6987
6988 static gboolean
6989 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6990 {
6991         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6992
6993         return b == NULL || b == bb;
6994 }
6995
6996 static int
6997 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6998 {
6999         unsigned char *ip = start;
7000         unsigned char *target;
7001         int i;
7002         guint cli_addr;
7003         MonoBasicBlock *bblock;
7004         const MonoOpcode *opcode;
7005
7006         while (ip < end) {
7007                 cli_addr = ip - start;
7008                 i = mono_opcode_value ((const guint8 **)&ip, end);
7009                 if (i < 0)
7010                         UNVERIFIED;
7011                 opcode = &mono_opcodes [i];
7012                 switch (opcode->argument) {
7013                 case MonoInlineNone:
7014                         ip++; 
7015                         break;
7016                 case MonoInlineString:
7017                 case MonoInlineType:
7018                 case MonoInlineField:
7019                 case MonoInlineMethod:
7020                 case MonoInlineTok:
7021                 case MonoInlineSig:
7022                 case MonoShortInlineR:
7023                 case MonoInlineI:
7024                         ip += 5;
7025                         break;
7026                 case MonoInlineVar:
7027                         ip += 3;
7028                         break;
7029                 case MonoShortInlineVar:
7030                 case MonoShortInlineI:
7031                         ip += 2;
7032                         break;
7033                 case MonoShortInlineBrTarget:
7034                         target = start + cli_addr + 2 + (signed char)ip [1];
7035                         GET_BBLOCK (cfg, bblock, target);
7036                         ip += 2;
7037                         if (ip < end)
7038                                 GET_BBLOCK (cfg, bblock, ip);
7039                         break;
7040                 case MonoInlineBrTarget:
7041                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7042                         GET_BBLOCK (cfg, bblock, target);
7043                         ip += 5;
7044                         if (ip < end)
7045                                 GET_BBLOCK (cfg, bblock, ip);
7046                         break;
7047                 case MonoInlineSwitch: {
7048                         guint32 n = read32 (ip + 1);
7049                         guint32 j;
7050                         ip += 5;
7051                         cli_addr += 5 + 4 * n;
7052                         target = start + cli_addr;
7053                         GET_BBLOCK (cfg, bblock, target);
7054                         
7055                         for (j = 0; j < n; ++j) {
7056                                 target = start + cli_addr + (gint32)read32 (ip);
7057                                 GET_BBLOCK (cfg, bblock, target);
7058                                 ip += 4;
7059                         }
7060                         break;
7061                 }
7062                 case MonoInlineR:
7063                 case MonoInlineI8:
7064                         ip += 9;
7065                         break;
7066                 default:
7067                         g_assert_not_reached ();
7068                 }
7069
7070                 if (i == CEE_THROW) {
7071                         unsigned char *bb_start = ip - 1;
7072                         
7073                         /* Find the start of the bblock containing the throw */
7074                         bblock = NULL;
7075                         while ((bb_start >= start) && !bblock) {
7076                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7077                                 bb_start --;
7078                         }
7079                         if (bblock)
7080                                 bblock->out_of_line = 1;
7081                 }
7082         }
7083         return 0;
7084 unverified:
7085 exception_exit:
7086         *pos = ip;
7087         return 1;
7088 }
7089
7090 static inline MonoMethod *
7091 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7092 {
7093         MonoMethod *method;
7094
7095         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7096                 method = mono_method_get_wrapper_data (m, token);
7097                 if (context) {
7098                         MonoError error;
7099                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7100                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7101                 }
7102         } else {
7103                 method = mono_get_method_full (m->klass->image, token, klass, context);
7104         }
7105
7106         return method;
7107 }
7108
7109 static inline MonoMethod *
7110 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7111 {
7112         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7113
7114         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7115                 return NULL;
7116
7117         return method;
7118 }
7119
7120 static inline MonoClass*
7121 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7122 {
7123         MonoError error;
7124         MonoClass *klass;
7125
7126         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7127                 klass = mono_method_get_wrapper_data (method, token);
7128                 if (context)
7129                         klass = mono_class_inflate_generic_class (klass, context);
7130         } else {
7131                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7132                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7133         }
7134         if (klass)
7135                 mono_class_init (klass);
7136         return klass;
7137 }
7138
7139 static inline MonoMethodSignature*
7140 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7141 {
7142         MonoMethodSignature *fsig;
7143
7144         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7145                 MonoError error;
7146
7147                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7148                 if (context) {
7149                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7150                         // FIXME:
7151                         g_assert (mono_error_ok (&error));
7152                 }
7153         } else {
7154                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7155         }
7156         return fsig;
7157 }
7158
7159 /*
7160  * Returns TRUE if the JIT should abort inlining because "callee"
7161  * is influenced by security attributes.
7162  */
7163 static
7164 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7165 {
7166         guint32 result;
7167         
7168         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
7169                 return TRUE;
7170         }
7171         
7172         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
7173         if (result == MONO_JIT_SECURITY_OK)
7174                 return FALSE;
7175
7176         if (result == MONO_JIT_LINKDEMAND_ECMA) {
7177                 /* Generate code to throw a SecurityException before the actual call/link */
7178                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7179                 MonoInst *args [2];
7180
7181                 NEW_ICONST (cfg, args [0], 4);
7182                 NEW_METHODCONST (cfg, args [1], caller);
7183                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
7184         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
7185                  /* don't hide previous results */
7186                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
7187                 cfg->exception_data = result;
7188                 return TRUE;
7189         }
7190         
7191         return FALSE;
7192 }
7193
7194 static MonoMethod*
7195 throw_exception (void)
7196 {
7197         static MonoMethod *method = NULL;
7198
7199         if (!method) {
7200                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7201                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7202         }
7203         g_assert (method);
7204         return method;
7205 }
7206
7207 static void
7208 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7209 {
7210         MonoMethod *thrower = throw_exception ();
7211         MonoInst *args [1];
7212
7213         EMIT_NEW_PCONST (cfg, args [0], ex);
7214         mono_emit_method_call (cfg, thrower, args, NULL);
7215 }
7216
7217 /*
7218  * Return the original method is a wrapper is specified. We can only access 
7219  * the custom attributes from the original method.
7220  */
7221 static MonoMethod*
7222 get_original_method (MonoMethod *method)
7223 {
7224         if (method->wrapper_type == MONO_WRAPPER_NONE)
7225                 return method;
7226
7227         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7228         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7229                 return NULL;
7230
7231         /* in other cases we need to find the original method */
7232         return mono_marshal_method_from_wrapper (method);
7233 }
7234
7235 static void
7236 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
7237                                           MonoBasicBlock *bblock, unsigned char *ip)
7238 {
7239         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7240         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7241         if (ex)
7242                 emit_throw_exception (cfg, ex);
7243 }
7244
7245 static void
7246 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
7247                                          MonoBasicBlock *bblock, unsigned char *ip)
7248 {
7249         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7250         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7251         if (ex)
7252                 emit_throw_exception (cfg, ex);
7253 }
7254
7255 /*
7256  * Check that the IL instructions at ip are the array initialization
7257  * sequence and return the pointer to the data and the size.
7258  */
7259 static const char*
7260 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7261 {
7262         /*
7263          * newarr[System.Int32]
7264          * dup
7265          * ldtoken field valuetype ...
7266          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7267          */
7268         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7269                 MonoError error;
7270                 guint32 token = read32 (ip + 7);
7271                 guint32 field_token = read32 (ip + 2);
7272                 guint32 field_index = field_token & 0xffffff;
7273                 guint32 rva;
7274                 const char *data_ptr;
7275                 int size = 0;
7276                 MonoMethod *cmethod;
7277                 MonoClass *dummy_class;
7278                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7279                 int dummy_align;
7280
7281                 if (!field) {
7282                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7283                         return NULL;
7284                 }
7285
7286                 *out_field_token = field_token;
7287
7288                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7289                 if (!cmethod)
7290                         return NULL;
7291                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7292                         return NULL;
7293                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7294                 case MONO_TYPE_BOOLEAN:
7295                 case MONO_TYPE_I1:
7296                 case MONO_TYPE_U1:
7297                         size = 1; break;
7298                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7299 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7300                 case MONO_TYPE_CHAR:
7301                 case MONO_TYPE_I2:
7302                 case MONO_TYPE_U2:
7303                         size = 2; break;
7304                 case MONO_TYPE_I4:
7305                 case MONO_TYPE_U4:
7306                 case MONO_TYPE_R4:
7307                         size = 4; break;
7308                 case MONO_TYPE_R8:
7309                 case MONO_TYPE_I8:
7310                 case MONO_TYPE_U8:
7311                         size = 8; break;
7312 #endif
7313                 default:
7314                         return NULL;
7315                 }
7316                 size *= len;
7317                 if (size > mono_type_size (field->type, &dummy_align))
7318                     return NULL;
7319                 *out_size = size;
7320                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7321                 if (!image_is_dynamic (method->klass->image)) {
7322                         field_index = read32 (ip + 2) & 0xffffff;
7323                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7324                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7325                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7326                         /* for aot code we do the lookup on load */
7327                         if (aot && data_ptr)
7328                                 return GUINT_TO_POINTER (rva);
7329                 } else {
7330                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7331                         g_assert (!aot);
7332                         data_ptr = mono_field_get_data (field);
7333                 }
7334                 return data_ptr;
7335         }
7336         return NULL;
7337 }
7338
7339 static void
7340 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7341 {
7342         char *method_fname = mono_method_full_name (method, TRUE);
7343         char *method_code;
7344         MonoMethodHeader *header = mono_method_get_header (method);
7345
7346         if (header->code_size == 0)
7347                 method_code = g_strdup ("method body is empty.");
7348         else
7349                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7350         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7351         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7352         g_free (method_fname);
7353         g_free (method_code);
7354         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7355 }
7356
7357 static void
7358 set_exception_object (MonoCompile *cfg, MonoException *exception)
7359 {
7360         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7361         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7362         cfg->exception_ptr = exception;
7363 }
7364
7365 static void
7366 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7367 {
7368         MonoInst *ins;
7369         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7370         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7371                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7372                 /* Optimize reg-reg moves away */
7373                 /* 
7374                  * Can't optimize other opcodes, since sp[0] might point to
7375                  * the last ins of a decomposed opcode.
7376                  */
7377                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7378         } else {
7379                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7380         }
7381 }
7382
7383 /*
7384  * ldloca inhibits many optimizations so try to get rid of it in common
7385  * cases.
7386  */
7387 static inline unsigned char *
7388 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7389 {
7390         int local, token;
7391         MonoClass *klass;
7392         MonoType *type;
7393
7394         if (size == 1) {
7395                 local = ip [1];
7396                 ip += 2;
7397         } else {
7398                 local = read16 (ip + 2);
7399                 ip += 4;
7400         }
7401         
7402         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7403                 /* From the INITOBJ case */
7404                 token = read32 (ip + 2);
7405                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7406                 CHECK_TYPELOAD (klass);
7407                 type = mini_get_underlying_type (cfg, &klass->byval_arg);
7408                 emit_init_local (cfg, local, type, TRUE);
7409                 return ip + 6;
7410         }
7411  exception_exit:
7412         return NULL;
7413 }
7414
7415 static gboolean
7416 is_exception_class (MonoClass *class)
7417 {
7418         while (class) {
7419                 if (class == mono_defaults.exception_class)
7420                         return TRUE;
7421                 class = class->parent;
7422         }
7423         return FALSE;
7424 }
7425
7426 /*
7427  * is_jit_optimizer_disabled:
7428  *
7429  *   Determine whenever M's assembly has a DebuggableAttribute with the
7430  * IsJITOptimizerDisabled flag set.
7431  */
7432 static gboolean
7433 is_jit_optimizer_disabled (MonoMethod *m)
7434 {
7435         MonoAssembly *ass = m->klass->image->assembly;
7436         MonoCustomAttrInfo* attrs;
7437         static MonoClass *klass;
7438         int i;
7439         gboolean val = FALSE;
7440
7441         g_assert (ass);
7442         if (ass->jit_optimizer_disabled_inited)
7443                 return ass->jit_optimizer_disabled;
7444
7445         if (!klass)
7446                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7447         if (!klass) {
7448                 /* Linked away */
7449                 ass->jit_optimizer_disabled = FALSE;
7450                 mono_memory_barrier ();
7451                 ass->jit_optimizer_disabled_inited = TRUE;
7452                 return FALSE;
7453         }
7454
7455         attrs = mono_custom_attrs_from_assembly (ass);
7456         if (attrs) {
7457                 for (i = 0; i < attrs->num_attrs; ++i) {
7458                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7459                         const gchar *p;
7460                         int len;
7461                         MonoMethodSignature *sig;
7462
7463                         if (!attr->ctor || attr->ctor->klass != klass)
7464                                 continue;
7465                         /* Decode the attribute. See reflection.c */
7466                         len = attr->data_size;
7467                         p = (const char*)attr->data;
7468                         g_assert (read16 (p) == 0x0001);
7469                         p += 2;
7470
7471                         // FIXME: Support named parameters
7472                         sig = mono_method_signature (attr->ctor);
7473                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7474                                 continue;
7475                         /* Two boolean arguments */
7476                         p ++;
7477                         val = *p;
7478                 }
7479                 mono_custom_attrs_free (attrs);
7480         }
7481
7482         ass->jit_optimizer_disabled = val;
7483         mono_memory_barrier ();
7484         ass->jit_optimizer_disabled_inited = TRUE;
7485
7486         return val;
7487 }
7488
7489 static gboolean
7490 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7491 {
7492         gboolean supported_tail_call;
7493         int i;
7494
7495 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7496         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7497 #else
7498         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7499 #endif
7500
7501         for (i = 0; i < fsig->param_count; ++i) {
7502                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7503                         /* These can point to the current method's stack */
7504                         supported_tail_call = FALSE;
7505         }
7506         if (fsig->hasthis && cmethod->klass->valuetype)
7507                 /* this might point to the current method's stack */
7508                 supported_tail_call = FALSE;
7509         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7510                 supported_tail_call = FALSE;
7511         if (cfg->method->save_lmf)
7512                 supported_tail_call = FALSE;
7513         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7514                 supported_tail_call = FALSE;
7515         if (call_opcode != CEE_CALL)
7516                 supported_tail_call = FALSE;
7517
7518         /* Debugging support */
7519 #if 0
7520         if (supported_tail_call) {
7521                 if (!mono_debug_count ())
7522                         supported_tail_call = FALSE;
7523         }
7524 #endif
7525
7526         return supported_tail_call;
7527 }
7528
7529 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7530  * it to the thread local value based on the tls_offset field. Every other kind of access to
7531  * the field causes an assert.
7532  */
7533 static gboolean
7534 is_magic_tls_access (MonoClassField *field)
7535 {
7536         if (strcmp (field->name, "tlsdata"))
7537                 return FALSE;
7538         if (strcmp (field->parent->name, "ThreadLocal`1"))
7539                 return FALSE;
7540         return field->parent->image == mono_defaults.corlib;
7541 }
7542
7543 /* emits the code needed to access a managed tls var (like ThreadStatic)
7544  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7545  * pointer for the current thread.
7546  * Returns the MonoInst* representing the address of the tls var.
7547  */
7548 static MonoInst*
7549 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7550 {
7551         MonoInst *addr;
7552         int static_data_reg, array_reg, dreg;
7553         int offset2_reg, idx_reg;
7554         // inlined access to the tls data
7555         // idx = (offset >> 24) - 1;
7556         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7557         static_data_reg = alloc_ireg (cfg);
7558         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7559         idx_reg = alloc_ireg (cfg);
7560         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7561         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7562         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7563         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7564         array_reg = alloc_ireg (cfg);
7565         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7566         offset2_reg = alloc_ireg (cfg);
7567         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7568         dreg = alloc_ireg (cfg);
7569         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7570         return addr;
7571 }
7572
7573 /*
7574  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7575  * this address is cached per-method in cached_tls_addr.
7576  */
7577 static MonoInst*
7578 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7579 {
7580         MonoInst *load, *addr, *temp, *store, *thread_ins;
7581         MonoClassField *offset_field;
7582
7583         if (*cached_tls_addr) {
7584                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7585                 return addr;
7586         }
7587         thread_ins = mono_get_thread_intrinsic (cfg);
7588         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7589
7590         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7591         if (thread_ins) {
7592                 MONO_ADD_INS (cfg->cbb, thread_ins);
7593         } else {
7594                 MonoMethod *thread_method;
7595                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7596                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7597         }
7598         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7599         addr->klass = mono_class_from_mono_type (tls_field->type);
7600         addr->type = STACK_MP;
7601         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7602         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7603
7604         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7605         return addr;
7606 }
7607
7608 /*
7609  * handle_ctor_call:
7610  *
7611  *   Handle calls made to ctors from NEWOBJ opcodes.
7612  *
7613  *   REF_BBLOCK will point to the current bblock after the call.
7614  */
7615 static void
7616 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7617                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7618 {
7619         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7620         MonoBasicBlock *bblock = *ref_bblock;
7621
7622         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7623                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7624                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7625                         mono_class_vtable (cfg->domain, cmethod->klass);
7626                         CHECK_TYPELOAD (cmethod->klass);
7627
7628                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7629                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7630                 } else {
7631                         if (context_used) {
7632                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7633                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7634                         } else {
7635                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7636
7637                                 CHECK_TYPELOAD (cmethod->klass);
7638                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7639                         }
7640                 }
7641         }
7642
7643         /* Avoid virtual calls to ctors if possible */
7644         if (mono_class_is_marshalbyref (cmethod->klass))
7645                 callvirt_this_arg = sp [0];
7646
7647         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7648                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7649                 CHECK_CFG_EXCEPTION;
7650         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7651                            mono_method_check_inlining (cfg, cmethod) &&
7652                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7653                 int costs;
7654
7655                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7656                         cfg->real_offset += 5;
7657
7658                         *inline_costs += costs - 5;
7659                         *ref_bblock = bblock;
7660                 } else {
7661                         INLINE_FAILURE ("inline failure");
7662                         // FIXME-VT: Clean this up
7663                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7664                                 GSHAREDVT_FAILURE(*ip);
7665                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7666                 }
7667         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7668                 MonoInst *addr;
7669
7670                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7671                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7672         } else if (context_used &&
7673                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7674                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7675                 MonoInst *cmethod_addr;
7676
7677                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7678
7679                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7680                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7681
7682                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7683         } else {
7684                 INLINE_FAILURE ("ctor call");
7685                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7686                                                                                   callvirt_this_arg, NULL, vtable_arg);
7687         }
7688  exception_exit:
7689         return;
7690 }
7691
7692 /*
7693  * mono_method_to_ir:
7694  *
7695  *   Translate the .net IL into linear IR.
7696  */
7697 int
7698 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7699                    MonoInst *return_var, MonoInst **inline_args, 
7700                    guint inline_offset, gboolean is_virtual_call)
7701 {
7702         MonoError error;
7703         MonoInst *ins, **sp, **stack_start;
7704         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7705         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7706         MonoMethod *cmethod, *method_definition;
7707         MonoInst **arg_array;
7708         MonoMethodHeader *header;
7709         MonoImage *image;
7710         guint32 token, ins_flag;
7711         MonoClass *klass;
7712         MonoClass *constrained_call = NULL;
7713         unsigned char *ip, *end, *target, *err_pos;
7714         MonoMethodSignature *sig;
7715         MonoGenericContext *generic_context = NULL;
7716         MonoGenericContainer *generic_container = NULL;
7717         MonoType **param_types;
7718         int i, n, start_new_bblock, dreg;
7719         int num_calls = 0, inline_costs = 0;
7720         int breakpoint_id = 0;
7721         guint num_args;
7722         MonoBoolean security, pinvoke;
7723         MonoSecurityManager* secman = NULL;
7724         MonoDeclSecurityActions actions;
7725         GSList *class_inits = NULL;
7726         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7727         int context_used;
7728         gboolean init_locals, seq_points, skip_dead_blocks;
7729         gboolean sym_seq_points = FALSE;
7730         MonoInst *cached_tls_addr = NULL;
7731         MonoDebugMethodInfo *minfo;
7732         MonoBitSet *seq_point_locs = NULL;
7733         MonoBitSet *seq_point_set_locs = NULL;
7734
7735         cfg->disable_inline = is_jit_optimizer_disabled (method);
7736
7737         /* serialization and xdomain stuff may need access to private fields and methods */
7738         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7739         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7740         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7741         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7742         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7743         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7744
7745         dont_verify |= mono_security_smcs_hack_enabled ();
7746
7747         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7748         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7749         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7750         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7751         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7752
7753         image = method->klass->image;
7754         header = mono_method_get_header (method);
7755         if (!header) {
7756                 MonoLoaderError *error;
7757
7758                 if ((error = mono_loader_get_last_error ())) {
7759                         mono_cfg_set_exception (cfg, error->exception_type);
7760                 } else {
7761                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7762                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7763                 }
7764                 goto exception_exit;
7765         }
7766         generic_container = mono_method_get_generic_container (method);
7767         sig = mono_method_signature (method);
7768         num_args = sig->hasthis + sig->param_count;
7769         ip = (unsigned char*)header->code;
7770         cfg->cil_start = ip;
7771         end = ip + header->code_size;
7772         cfg->stat_cil_code_size += header->code_size;
7773
7774         seq_points = cfg->gen_seq_points && cfg->method == method;
7775 #ifdef PLATFORM_ANDROID
7776         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7777 #endif
7778
7779         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7780                 /* We could hit a seq point before attaching to the JIT (#8338) */
7781                 seq_points = FALSE;
7782         }
7783
7784         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7785                 minfo = mono_debug_lookup_method (method);
7786                 if (minfo) {
7787                         int i, n_il_offsets;
7788                         int *il_offsets;
7789                         int *line_numbers;
7790
7791                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7792                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7793                         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);
7794                         sym_seq_points = TRUE;
7795                         for (i = 0; i < n_il_offsets; ++i) {
7796                                 if (il_offsets [i] < header->code_size)
7797                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7798                         }
7799                         g_free (il_offsets);
7800                         g_free (line_numbers);
7801                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7802                         /* Methods without line number info like auto-generated property accessors */
7803                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7804                         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);
7805                         sym_seq_points = TRUE;
7806                 }
7807         }
7808
7809         /* 
7810          * Methods without init_locals set could cause asserts in various passes
7811          * (#497220). To work around this, we emit dummy initialization opcodes
7812          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7813          * on some platforms.
7814          */
7815         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7816                 init_locals = header->init_locals;
7817         else
7818                 init_locals = TRUE;
7819
7820         method_definition = method;
7821         while (method_definition->is_inflated) {
7822                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7823                 method_definition = imethod->declaring;
7824         }
7825
7826         /* SkipVerification is not allowed if core-clr is enabled */
7827         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7828                 dont_verify = TRUE;
7829                 dont_verify_stloc = TRUE;
7830         }
7831
7832         if (sig->is_inflated)
7833                 generic_context = mono_method_get_context (method);
7834         else if (generic_container)
7835                 generic_context = &generic_container->context;
7836         cfg->generic_context = generic_context;
7837
7838         if (!cfg->generic_sharing_context)
7839                 g_assert (!sig->has_type_parameters);
7840
7841         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7842                 g_assert (method->is_inflated);
7843                 g_assert (mono_method_get_context (method)->method_inst);
7844         }
7845         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7846                 g_assert (sig->generic_param_count);
7847
7848         if (cfg->method == method) {
7849                 cfg->real_offset = 0;
7850         } else {
7851                 cfg->real_offset = inline_offset;
7852         }
7853
7854         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7855         cfg->cil_offset_to_bb_len = header->code_size;
7856
7857         cfg->current_method = method;
7858
7859         if (cfg->verbose_level > 2)
7860                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7861
7862         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7863         if (sig->hasthis)
7864                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7865         for (n = 0; n < sig->param_count; ++n)
7866                 param_types [n + sig->hasthis] = sig->params [n];
7867         cfg->arg_types = param_types;
7868
7869         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7870         if (cfg->method == method) {
7871
7872                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7873                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7874
7875                 /* ENTRY BLOCK */
7876                 NEW_BBLOCK (cfg, start_bblock);
7877                 cfg->bb_entry = start_bblock;
7878                 start_bblock->cil_code = NULL;
7879                 start_bblock->cil_length = 0;
7880 #if defined(__native_client_codegen__)
7881                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7882                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7883                 MONO_ADD_INS (start_bblock, ins);
7884 #endif
7885
7886                 /* EXIT BLOCK */
7887                 NEW_BBLOCK (cfg, end_bblock);
7888                 cfg->bb_exit = end_bblock;
7889                 end_bblock->cil_code = NULL;
7890                 end_bblock->cil_length = 0;
7891                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7892                 g_assert (cfg->num_bblocks == 2);
7893
7894                 arg_array = cfg->args;
7895
7896                 if (header->num_clauses) {
7897                         cfg->spvars = g_hash_table_new (NULL, NULL);
7898                         cfg->exvars = g_hash_table_new (NULL, NULL);
7899                 }
7900                 /* handle exception clauses */
7901                 for (i = 0; i < header->num_clauses; ++i) {
7902                         MonoBasicBlock *try_bb;
7903                         MonoExceptionClause *clause = &header->clauses [i];
7904                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7905                         try_bb->real_offset = clause->try_offset;
7906                         try_bb->try_start = TRUE;
7907                         try_bb->region = ((i + 1) << 8) | clause->flags;
7908                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7909                         tblock->real_offset = clause->handler_offset;
7910                         tblock->flags |= BB_EXCEPTION_HANDLER;
7911
7912                         /*
7913                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7914                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7915                          */
7916                         if (COMPILE_LLVM (cfg))
7917                                 link_bblock (cfg, try_bb, tblock);
7918
7919                         if (*(ip + clause->handler_offset) == CEE_POP)
7920                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7921
7922                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7923                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7924                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7925                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7926                                 MONO_ADD_INS (tblock, ins);
7927
7928                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7929                                         /* finally clauses already have a seq point */
7930                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7931                                         MONO_ADD_INS (tblock, ins);
7932                                 }
7933
7934                                 /* todo: is a fault block unsafe to optimize? */
7935                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7936                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7937                         }
7938
7939
7940                         /*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);
7941                           while (p < end) {
7942                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7943                           }*/
7944                         /* catch and filter blocks get the exception object on the stack */
7945                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7946                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7947                                 MonoInst *dummy_use;
7948
7949                                 /* mostly like handle_stack_args (), but just sets the input args */
7950                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7951                                 tblock->in_scount = 1;
7952                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7953                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7954
7955                                 /* 
7956                                  * Add a dummy use for the exvar so its liveness info will be
7957                                  * correct.
7958                                  */
7959                                 cfg->cbb = tblock;
7960                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7961                                 
7962                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7963                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7964                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7965                                         tblock->real_offset = clause->data.filter_offset;
7966                                         tblock->in_scount = 1;
7967                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7968                                         /* The filter block shares the exvar with the handler block */
7969                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7970                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7971                                         MONO_ADD_INS (tblock, ins);
7972                                 }
7973                         }
7974
7975                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7976                                         clause->data.catch_class &&
7977                                         cfg->generic_sharing_context &&
7978                                         mono_class_check_context_used (clause->data.catch_class)) {
7979                                 /*
7980                                  * In shared generic code with catch
7981                                  * clauses containing type variables
7982                                  * the exception handling code has to
7983                                  * be able to get to the rgctx.
7984                                  * Therefore we have to make sure that
7985                                  * the vtable/mrgctx argument (for
7986                                  * static or generic methods) or the
7987                                  * "this" argument (for non-static
7988                                  * methods) are live.
7989                                  */
7990                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7991                                                 mini_method_get_context (method)->method_inst ||
7992                                                 method->klass->valuetype) {
7993                                         mono_get_vtable_var (cfg);
7994                                 } else {
7995                                         MonoInst *dummy_use;
7996
7997                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7998                                 }
7999                         }
8000                 }
8001         } else {
8002                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8003                 cfg->cbb = start_bblock;
8004                 cfg->args = arg_array;
8005                 mono_save_args (cfg, sig, inline_args);
8006         }
8007
8008         /* FIRST CODE BLOCK */
8009         NEW_BBLOCK (cfg, bblock);
8010         bblock->cil_code = ip;
8011         cfg->cbb = bblock;
8012         cfg->ip = ip;
8013
8014         ADD_BBLOCK (cfg, bblock);
8015
8016         if (cfg->method == method) {
8017                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8018                 if (breakpoint_id) {
8019                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8020                         MONO_ADD_INS (bblock, ins);
8021                 }
8022         }
8023
8024         if (mono_security_cas_enabled ())
8025                 secman = mono_security_manager_get_methods ();
8026
8027         security = (secman && mono_security_method_has_declsec (method));
8028         /* at this point having security doesn't mean we have any code to generate */
8029         if (security && (cfg->method == method)) {
8030                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
8031                  * And we do not want to enter the next section (with allocation) if we
8032                  * have nothing to generate */
8033                 security = mono_declsec_get_demands (method, &actions);
8034         }
8035
8036         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
8037         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
8038         if (pinvoke) {
8039                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8040                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8041                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
8042
8043                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
8044                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8045                                 pinvoke = FALSE;
8046                         }
8047                         if (custom)
8048                                 mono_custom_attrs_free (custom);
8049
8050                         if (pinvoke) {
8051                                 custom = mono_custom_attrs_from_class (wrapped->klass);
8052                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8053                                         pinvoke = FALSE;
8054                                 }
8055                                 if (custom)
8056                                         mono_custom_attrs_free (custom);
8057                         }
8058                 } else {
8059                         /* not a P/Invoke after all */
8060                         pinvoke = FALSE;
8061                 }
8062         }
8063         
8064         /* we use a separate basic block for the initialization code */
8065         NEW_BBLOCK (cfg, init_localsbb);
8066         cfg->bb_init = init_localsbb;
8067         init_localsbb->real_offset = cfg->real_offset;
8068         start_bblock->next_bb = init_localsbb;
8069         init_localsbb->next_bb = bblock;
8070         link_bblock (cfg, start_bblock, init_localsbb);
8071         link_bblock (cfg, init_localsbb, bblock);
8072                 
8073         cfg->cbb = init_localsbb;
8074
8075         if (cfg->gsharedvt && cfg->method == method) {
8076                 MonoGSharedVtMethodInfo *info;
8077                 MonoInst *var, *locals_var;
8078                 int dreg;
8079
8080                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8081                 info->method = cfg->method;
8082                 info->count_entries = 16;
8083                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8084                 cfg->gsharedvt_info = info;
8085
8086                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8087                 /* prevent it from being register allocated */
8088                 //var->flags |= MONO_INST_VOLATILE;
8089                 cfg->gsharedvt_info_var = var;
8090
8091                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8092                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8093
8094                 /* Allocate locals */
8095                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8096                 /* prevent it from being register allocated */
8097                 //locals_var->flags |= MONO_INST_VOLATILE;
8098                 cfg->gsharedvt_locals_var = locals_var;
8099
8100                 dreg = alloc_ireg (cfg);
8101                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8102
8103                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8104                 ins->dreg = locals_var->dreg;
8105                 ins->sreg1 = dreg;
8106                 MONO_ADD_INS (cfg->cbb, ins);
8107                 cfg->gsharedvt_locals_var_ins = ins;
8108                 
8109                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8110                 /*
8111                 if (init_locals)
8112                         ins->flags |= MONO_INST_INIT;
8113                 */
8114         }
8115
8116         /* at this point we know, if security is TRUE, that some code needs to be generated */
8117         if (security && (cfg->method == method)) {
8118                 MonoInst *args [2];
8119
8120                 cfg->stat_cas_demand_generation++;
8121
8122                 if (actions.demand.blob) {
8123                         /* Add code for SecurityAction.Demand */
8124                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
8125                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
8126                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8127                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8128                 }
8129                 if (actions.noncasdemand.blob) {
8130                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
8131                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
8132                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
8133                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
8134                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8135                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8136                 }
8137                 if (actions.demandchoice.blob) {
8138                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
8139                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
8140                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
8141                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
8142                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
8143                 }
8144         }
8145
8146         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
8147         if (pinvoke) {
8148                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
8149         }
8150
8151         if (mono_security_core_clr_enabled ()) {
8152                 /* check if this is native code, e.g. an icall or a p/invoke */
8153                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8154                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8155                         if (wrapped) {
8156                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8157                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8158
8159                                 /* if this ia a native call then it can only be JITted from platform code */
8160                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8161                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8162                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8163                                                         mono_get_exception_method_access ();
8164                                                 emit_throw_exception (cfg, ex);
8165                                         }
8166                                 }
8167                         }
8168                 }
8169         }
8170
8171         CHECK_CFG_EXCEPTION;
8172
8173         if (header->code_size == 0)
8174                 UNVERIFIED;
8175
8176         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8177                 ip = err_pos;
8178                 UNVERIFIED;
8179         }
8180
8181         if (cfg->method == method)
8182                 mono_debug_init_method (cfg, bblock, breakpoint_id);
8183
8184         for (n = 0; n < header->num_locals; ++n) {
8185                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8186                         UNVERIFIED;
8187         }
8188         class_inits = NULL;
8189
8190         /* We force the vtable variable here for all shared methods
8191            for the possibility that they might show up in a stack
8192            trace where their exact instantiation is needed. */
8193         if (cfg->generic_sharing_context && method == cfg->method) {
8194                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8195                                 mini_method_get_context (method)->method_inst ||
8196                                 method->klass->valuetype) {
8197                         mono_get_vtable_var (cfg);
8198                 } else {
8199                         /* FIXME: Is there a better way to do this?
8200                            We need the variable live for the duration
8201                            of the whole method. */
8202                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8203                 }
8204         }
8205
8206         /* add a check for this != NULL to inlined methods */
8207         if (is_virtual_call) {
8208                 MonoInst *arg_ins;
8209
8210                 NEW_ARGLOAD (cfg, arg_ins, 0);
8211                 MONO_ADD_INS (cfg->cbb, arg_ins);
8212                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8213         }
8214
8215         skip_dead_blocks = !dont_verify;
8216         if (skip_dead_blocks) {
8217                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8218                 CHECK_CFG_ERROR;
8219                 g_assert (bb);
8220         }
8221
8222         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8223         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8224
8225         ins_flag = 0;
8226         start_new_bblock = 0;
8227         cfg->cbb = bblock;
8228         while (ip < end) {
8229                 if (cfg->method == method)
8230                         cfg->real_offset = ip - header->code;
8231                 else
8232                         cfg->real_offset = inline_offset;
8233                 cfg->ip = ip;
8234
8235                 context_used = 0;
8236                 
8237                 if (start_new_bblock) {
8238                         bblock->cil_length = ip - bblock->cil_code;
8239                         if (start_new_bblock == 2) {
8240                                 g_assert (ip == tblock->cil_code);
8241                         } else {
8242                                 GET_BBLOCK (cfg, tblock, ip);
8243                         }
8244                         bblock->next_bb = tblock;
8245                         bblock = tblock;
8246                         cfg->cbb = bblock;
8247                         start_new_bblock = 0;
8248                         for (i = 0; i < bblock->in_scount; ++i) {
8249                                 if (cfg->verbose_level > 3)
8250                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8251                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8252                                 *sp++ = ins;
8253                         }
8254                         if (class_inits)
8255                                 g_slist_free (class_inits);
8256                         class_inits = NULL;
8257                 } else {
8258                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
8259                                 link_bblock (cfg, bblock, tblock);
8260                                 if (sp != stack_start) {
8261                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8262                                         sp = stack_start;
8263                                         CHECK_UNVERIFIABLE (cfg);
8264                                 }
8265                                 bblock->next_bb = tblock;
8266                                 bblock = tblock;
8267                                 cfg->cbb = bblock;
8268                                 for (i = 0; i < bblock->in_scount; ++i) {
8269                                         if (cfg->verbose_level > 3)
8270                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8271                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8272                                         *sp++ = ins;
8273                                 }
8274                                 g_slist_free (class_inits);
8275                                 class_inits = NULL;
8276                         }
8277                 }
8278
8279                 if (skip_dead_blocks) {
8280                         int ip_offset = ip - header->code;
8281
8282                         if (ip_offset == bb->end)
8283                                 bb = bb->next;
8284
8285                         if (bb->dead) {
8286                                 int op_size = mono_opcode_size (ip, end);
8287                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8288
8289                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8290
8291                                 if (ip_offset + op_size == bb->end) {
8292                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8293                                         MONO_ADD_INS (bblock, ins);
8294                                         start_new_bblock = 1;
8295                                 }
8296
8297                                 ip += op_size;
8298                                 continue;
8299                         }
8300                 }
8301                 /*
8302                  * Sequence points are points where the debugger can place a breakpoint.
8303                  * Currently, we generate these automatically at points where the IL
8304                  * stack is empty.
8305                  */
8306                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8307                         /*
8308                          * Make methods interruptable at the beginning, and at the targets of
8309                          * backward branches.
8310                          * Also, do this at the start of every bblock in methods with clauses too,
8311                          * to be able to handle instructions with inprecise control flow like
8312                          * throw/endfinally.
8313                          * Backward branches are handled at the end of method-to-ir ().
8314                          */
8315                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8316
8317                         /* Avoid sequence points on empty IL like .volatile */
8318                         // FIXME: Enable this
8319                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8320                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8321                         if (sp != stack_start)
8322                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8323                         MONO_ADD_INS (cfg->cbb, ins);
8324
8325                         if (sym_seq_points)
8326                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8327                 }
8328
8329                 bblock->real_offset = cfg->real_offset;
8330
8331                 if ((cfg->method == method) && cfg->coverage_info) {
8332                         guint32 cil_offset = ip - header->code;
8333                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8334
8335                         /* TODO: Use an increment here */
8336 #if defined(TARGET_X86)
8337                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8338                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8339                         ins->inst_imm = 1;
8340                         MONO_ADD_INS (cfg->cbb, ins);
8341 #else
8342                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8343                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8344 #endif
8345                 }
8346
8347                 if (cfg->verbose_level > 3)
8348                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8349
8350                 switch (*ip) {
8351                 case CEE_NOP:
8352                         if (seq_points && !sym_seq_points && sp != stack_start) {
8353                                 /*
8354                                  * The C# compiler uses these nops to notify the JIT that it should
8355                                  * insert seq points.
8356                                  */
8357                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8358                                 MONO_ADD_INS (cfg->cbb, ins);
8359                         }
8360                         if (cfg->keep_cil_nops)
8361                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8362                         else
8363                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8364                         ip++;
8365                         MONO_ADD_INS (bblock, ins);
8366                         break;
8367                 case CEE_BREAK:
8368                         if (should_insert_brekpoint (cfg->method)) {
8369                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8370                         } else {
8371                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8372                         }
8373                         ip++;
8374                         MONO_ADD_INS (bblock, ins);
8375                         break;
8376                 case CEE_LDARG_0:
8377                 case CEE_LDARG_1:
8378                 case CEE_LDARG_2:
8379                 case CEE_LDARG_3:
8380                         CHECK_STACK_OVF (1);
8381                         n = (*ip)-CEE_LDARG_0;
8382                         CHECK_ARG (n);
8383                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8384                         ip++;
8385                         *sp++ = ins;
8386                         break;
8387                 case CEE_LDLOC_0:
8388                 case CEE_LDLOC_1:
8389                 case CEE_LDLOC_2:
8390                 case CEE_LDLOC_3:
8391                         CHECK_STACK_OVF (1);
8392                         n = (*ip)-CEE_LDLOC_0;
8393                         CHECK_LOCAL (n);
8394                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8395                         ip++;
8396                         *sp++ = ins;
8397                         break;
8398                 case CEE_STLOC_0:
8399                 case CEE_STLOC_1:
8400                 case CEE_STLOC_2:
8401                 case CEE_STLOC_3: {
8402                         CHECK_STACK (1);
8403                         n = (*ip)-CEE_STLOC_0;
8404                         CHECK_LOCAL (n);
8405                         --sp;
8406                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8407                                 UNVERIFIED;
8408                         emit_stloc_ir (cfg, sp, header, n);
8409                         ++ip;
8410                         inline_costs += 1;
8411                         break;
8412                         }
8413                 case CEE_LDARG_S:
8414                         CHECK_OPSIZE (2);
8415                         CHECK_STACK_OVF (1);
8416                         n = ip [1];
8417                         CHECK_ARG (n);
8418                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8419                         *sp++ = ins;
8420                         ip += 2;
8421                         break;
8422                 case CEE_LDARGA_S:
8423                         CHECK_OPSIZE (2);
8424                         CHECK_STACK_OVF (1);
8425                         n = ip [1];
8426                         CHECK_ARG (n);
8427                         NEW_ARGLOADA (cfg, ins, n);
8428                         MONO_ADD_INS (cfg->cbb, ins);
8429                         *sp++ = ins;
8430                         ip += 2;
8431                         break;
8432                 case CEE_STARG_S:
8433                         CHECK_OPSIZE (2);
8434                         CHECK_STACK (1);
8435                         --sp;
8436                         n = ip [1];
8437                         CHECK_ARG (n);
8438                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8439                                 UNVERIFIED;
8440                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8441                         ip += 2;
8442                         break;
8443                 case CEE_LDLOC_S:
8444                         CHECK_OPSIZE (2);
8445                         CHECK_STACK_OVF (1);
8446                         n = ip [1];
8447                         CHECK_LOCAL (n);
8448                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8449                         *sp++ = ins;
8450                         ip += 2;
8451                         break;
8452                 case CEE_LDLOCA_S: {
8453                         unsigned char *tmp_ip;
8454                         CHECK_OPSIZE (2);
8455                         CHECK_STACK_OVF (1);
8456                         CHECK_LOCAL (ip [1]);
8457
8458                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8459                                 ip = tmp_ip;
8460                                 inline_costs += 1;
8461                                 break;
8462                         }
8463
8464                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8465                         *sp++ = ins;
8466                         ip += 2;
8467                         break;
8468                 }
8469                 case CEE_STLOC_S:
8470                         CHECK_OPSIZE (2);
8471                         CHECK_STACK (1);
8472                         --sp;
8473                         CHECK_LOCAL (ip [1]);
8474                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8475                                 UNVERIFIED;
8476                         emit_stloc_ir (cfg, sp, header, ip [1]);
8477                         ip += 2;
8478                         inline_costs += 1;
8479                         break;
8480                 case CEE_LDNULL:
8481                         CHECK_STACK_OVF (1);
8482                         EMIT_NEW_PCONST (cfg, ins, NULL);
8483                         ins->type = STACK_OBJ;
8484                         ++ip;
8485                         *sp++ = ins;
8486                         break;
8487                 case CEE_LDC_I4_M1:
8488                         CHECK_STACK_OVF (1);
8489                         EMIT_NEW_ICONST (cfg, ins, -1);
8490                         ++ip;
8491                         *sp++ = ins;
8492                         break;
8493                 case CEE_LDC_I4_0:
8494                 case CEE_LDC_I4_1:
8495                 case CEE_LDC_I4_2:
8496                 case CEE_LDC_I4_3:
8497                 case CEE_LDC_I4_4:
8498                 case CEE_LDC_I4_5:
8499                 case CEE_LDC_I4_6:
8500                 case CEE_LDC_I4_7:
8501                 case CEE_LDC_I4_8:
8502                         CHECK_STACK_OVF (1);
8503                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8504                         ++ip;
8505                         *sp++ = ins;
8506                         break;
8507                 case CEE_LDC_I4_S:
8508                         CHECK_OPSIZE (2);
8509                         CHECK_STACK_OVF (1);
8510                         ++ip;
8511                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8512                         ++ip;
8513                         *sp++ = ins;
8514                         break;
8515                 case CEE_LDC_I4:
8516                         CHECK_OPSIZE (5);
8517                         CHECK_STACK_OVF (1);
8518                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8519                         ip += 5;
8520                         *sp++ = ins;
8521                         break;
8522                 case CEE_LDC_I8:
8523                         CHECK_OPSIZE (9);
8524                         CHECK_STACK_OVF (1);
8525                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8526                         ins->type = STACK_I8;
8527                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8528                         ++ip;
8529                         ins->inst_l = (gint64)read64 (ip);
8530                         MONO_ADD_INS (bblock, ins);
8531                         ip += 8;
8532                         *sp++ = ins;
8533                         break;
8534                 case CEE_LDC_R4: {
8535                         float *f;
8536                         gboolean use_aotconst = FALSE;
8537
8538 #ifdef TARGET_POWERPC
8539                         /* FIXME: Clean this up */
8540                         if (cfg->compile_aot)
8541                                 use_aotconst = TRUE;
8542 #endif
8543
8544                         /* FIXME: we should really allocate this only late in the compilation process */
8545                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8546                         CHECK_OPSIZE (5);
8547                         CHECK_STACK_OVF (1);
8548
8549                         if (use_aotconst) {
8550                                 MonoInst *cons;
8551                                 int dreg;
8552
8553                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8554
8555                                 dreg = alloc_freg (cfg);
8556                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8557                                 ins->type = cfg->r4_stack_type;
8558                         } else {
8559                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8560                                 ins->type = cfg->r4_stack_type;
8561                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8562                                 ins->inst_p0 = f;
8563                                 MONO_ADD_INS (bblock, ins);
8564                         }
8565                         ++ip;
8566                         readr4 (ip, f);
8567                         ip += 4;
8568                         *sp++ = ins;                    
8569                         break;
8570                 }
8571                 case CEE_LDC_R8: {
8572                         double *d;
8573                         gboolean use_aotconst = FALSE;
8574
8575 #ifdef TARGET_POWERPC
8576                         /* FIXME: Clean this up */
8577                         if (cfg->compile_aot)
8578                                 use_aotconst = TRUE;
8579 #endif
8580
8581                         /* FIXME: we should really allocate this only late in the compilation process */
8582                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8583                         CHECK_OPSIZE (9);
8584                         CHECK_STACK_OVF (1);
8585
8586                         if (use_aotconst) {
8587                                 MonoInst *cons;
8588                                 int dreg;
8589
8590                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8591
8592                                 dreg = alloc_freg (cfg);
8593                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8594                                 ins->type = STACK_R8;
8595                         } else {
8596                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8597                                 ins->type = STACK_R8;
8598                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8599                                 ins->inst_p0 = d;
8600                                 MONO_ADD_INS (bblock, ins);
8601                         }
8602                         ++ip;
8603                         readr8 (ip, d);
8604                         ip += 8;
8605                         *sp++ = ins;
8606                         break;
8607                 }
8608                 case CEE_DUP: {
8609                         MonoInst *temp, *store;
8610                         CHECK_STACK (1);
8611                         CHECK_STACK_OVF (1);
8612                         sp--;
8613                         ins = *sp;
8614
8615                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8616                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8617
8618                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8619                         *sp++ = ins;
8620
8621                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8622                         *sp++ = ins;
8623
8624                         ++ip;
8625                         inline_costs += 2;
8626                         break;
8627                 }
8628                 case CEE_POP:
8629                         CHECK_STACK (1);
8630                         ip++;
8631                         --sp;
8632
8633 #ifdef TARGET_X86
8634                         if (sp [0]->type == STACK_R8)
8635                                 /* we need to pop the value from the x86 FP stack */
8636                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8637 #endif
8638                         break;
8639                 case CEE_JMP: {
8640                         MonoCallInst *call;
8641
8642                         INLINE_FAILURE ("jmp");
8643                         GSHAREDVT_FAILURE (*ip);
8644
8645                         CHECK_OPSIZE (5);
8646                         if (stack_start != sp)
8647                                 UNVERIFIED;
8648                         token = read32 (ip + 1);
8649                         /* FIXME: check the signature matches */
8650                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8651
8652                         if (!cmethod || mono_loader_get_last_error ())
8653                                 LOAD_ERROR;
8654  
8655                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8656                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8657
8658                         if (mono_security_cas_enabled ())
8659                                 CHECK_CFG_EXCEPTION;
8660
8661                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8662
8663                         if (ARCH_HAVE_OP_TAIL_CALL) {
8664                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8665                                 int i, n;
8666
8667                                 /* Handle tail calls similarly to calls */
8668                                 n = fsig->param_count + fsig->hasthis;
8669
8670                                 DISABLE_AOT (cfg);
8671
8672                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8673                                 call->method = cmethod;
8674                                 call->tail_call = TRUE;
8675                                 call->signature = mono_method_signature (cmethod);
8676                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8677                                 call->inst.inst_p0 = cmethod;
8678                                 for (i = 0; i < n; ++i)
8679                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8680
8681                                 mono_arch_emit_call (cfg, call);
8682                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8683                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8684                         } else {
8685                                 for (i = 0; i < num_args; ++i)
8686                                         /* Prevent arguments from being optimized away */
8687                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8688
8689                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8690                                 ins = (MonoInst*)call;
8691                                 ins->inst_p0 = cmethod;
8692                                 MONO_ADD_INS (bblock, ins);
8693                         }
8694
8695                         ip += 5;
8696                         start_new_bblock = 1;
8697                         break;
8698                 }
8699                 case CEE_CALLI:
8700                 case CEE_CALL:
8701                 case CEE_CALLVIRT: {
8702                         MonoInst *addr = NULL;
8703                         MonoMethodSignature *fsig = NULL;
8704                         int array_rank = 0;
8705                         int virtual = *ip == CEE_CALLVIRT;
8706                         int calli = *ip == CEE_CALLI;
8707                         gboolean pass_imt_from_rgctx = FALSE;
8708                         MonoInst *imt_arg = NULL;
8709                         MonoInst *keep_this_alive = NULL;
8710                         gboolean pass_vtable = FALSE;
8711                         gboolean pass_mrgctx = FALSE;
8712                         MonoInst *vtable_arg = NULL;
8713                         gboolean check_this = FALSE;
8714                         gboolean supported_tail_call = FALSE;
8715                         gboolean tail_call = FALSE;
8716                         gboolean need_seq_point = FALSE;
8717                         guint32 call_opcode = *ip;
8718                         gboolean emit_widen = TRUE;
8719                         gboolean push_res = TRUE;
8720                         gboolean skip_ret = FALSE;
8721                         gboolean delegate_invoke = FALSE;
8722
8723                         CHECK_OPSIZE (5);
8724                         token = read32 (ip + 1);
8725
8726                         ins = NULL;
8727
8728                         if (calli) {
8729                                 //GSHAREDVT_FAILURE (*ip);
8730                                 cmethod = NULL;
8731                                 CHECK_STACK (1);
8732                                 --sp;
8733                                 addr = *sp;
8734                                 fsig = mini_get_signature (method, token, generic_context);
8735                                 n = fsig->param_count + fsig->hasthis;
8736
8737                                 if (method->dynamic && fsig->pinvoke) {
8738                                         MonoInst *args [3];
8739
8740                                         /*
8741                                          * This is a call through a function pointer using a pinvoke
8742                                          * signature. Have to create a wrapper and call that instead.
8743                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8744                                          * instead based on the signature.
8745                                          */
8746                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8747                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8748                                         args [2] = addr;
8749                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8750                                 }
8751                         } else {
8752                                 MonoMethod *cil_method;
8753
8754                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8755                                 cil_method = cmethod;
8756                                 
8757                                 if (constrained_call) {
8758                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8759                                                 if (cfg->verbose_level > 2)
8760                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8761                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
8762                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
8763                                                           cfg->generic_sharing_context)) {
8764                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context, &cfg->error);
8765                                                         CHECK_CFG_ERROR;
8766                                                 }
8767                                         } else {
8768                                                 if (cfg->verbose_level > 2)
8769                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8770
8771                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8772                                                         /* 
8773                                                          * This is needed since get_method_constrained can't find 
8774                                                          * the method in klass representing a type var.
8775                                                          * The type var is guaranteed to be a reference type in this
8776                                                          * case.
8777                                                          */
8778                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
8779                                                                 g_assert (!cmethod->klass->valuetype);
8780                                                 } else {
8781                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_call, generic_context, &cil_method, &cfg->error);
8782                                                         CHECK_CFG_ERROR;
8783                                                 }
8784                                         }
8785                                 }
8786                                         
8787                                 if (!cmethod || mono_loader_get_last_error ())
8788                                         LOAD_ERROR;
8789                                 if (!dont_verify && !cfg->skip_visibility) {
8790                                         MonoMethod *target_method = cil_method;
8791                                         if (method->is_inflated) {
8792                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8793                                         }
8794                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8795                                                 !mono_method_can_access_method (method, cil_method))
8796                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8797                                 }
8798
8799                                 if (mono_security_core_clr_enabled ())
8800                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8801
8802                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8803                                         /* MS.NET seems to silently convert this to a callvirt */
8804                                         virtual = 1;
8805
8806                                 {
8807                                         /*
8808                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8809                                          * converts to a callvirt.
8810                                          *
8811                                          * tests/bug-515884.il is an example of this behavior
8812                                          */
8813                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8814                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8815                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8816                                                 virtual = 1;
8817                                 }
8818
8819                                 if (!cmethod->klass->inited)
8820                                         if (!mono_class_init (cmethod->klass))
8821                                                 TYPE_LOAD_ERROR (cmethod->klass);
8822
8823                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8824                                     mini_class_is_system_array (cmethod->klass)) {
8825                                         array_rank = cmethod->klass->rank;
8826                                         fsig = mono_method_signature (cmethod);
8827                                 } else {
8828                                         fsig = mono_method_signature (cmethod);
8829
8830                                         if (!fsig)
8831                                                 LOAD_ERROR;
8832
8833                                         if (fsig->pinvoke) {
8834                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8835                                                         check_for_pending_exc, cfg->compile_aot);
8836                                                 fsig = mono_method_signature (wrapper);
8837                                         } else if (constrained_call) {
8838                                                 fsig = mono_method_signature (cmethod);
8839                                         } else {
8840                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8841                                                 CHECK_CFG_ERROR;
8842                                         }
8843                                 }
8844
8845                                 mono_save_token_info (cfg, image, token, cil_method);
8846
8847                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8848                                         need_seq_point = TRUE;
8849
8850                                 n = fsig->param_count + fsig->hasthis;
8851
8852                                 /* Don't support calls made using type arguments for now */
8853                                 /*
8854                                 if (cfg->gsharedvt) {
8855                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8856                                                 GSHAREDVT_FAILURE (*ip);
8857                                 }
8858                                 */
8859
8860                                 if (mono_security_cas_enabled ()) {
8861                                         if (check_linkdemand (cfg, method, cmethod))
8862                                                 INLINE_FAILURE ("linkdemand");
8863                                         CHECK_CFG_EXCEPTION;
8864                                 }
8865
8866                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8867                                         g_assert_not_reached ();
8868                         }
8869
8870                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8871                                 UNVERIFIED;
8872
8873                         if (!cfg->generic_sharing_context && cmethod)
8874                                 g_assert (!mono_method_check_context_used (cmethod));
8875
8876                         CHECK_STACK (n);
8877
8878                         //g_assert (!virtual || fsig->hasthis);
8879
8880                         sp -= n;
8881
8882                         if (constrained_call) {
8883                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
8884                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
8885                                                 /* The 'Own method' case below */
8886                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8887                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8888                                         } else {
8889                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_call, &emit_widen, &bblock);
8890                                                 CHECK_CFG_EXCEPTION;
8891                                                 g_assert (ins);
8892                                                 goto call_end;
8893                                         }
8894                                 }
8895
8896                                 /*
8897                                  * We have the `constrained.' prefix opcode.
8898                                  */
8899                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8900                                         /*
8901                                          * The type parameter is instantiated as a valuetype,
8902                                          * but that type doesn't override the method we're
8903                                          * calling, so we need to box `this'.
8904                                          */
8905                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8906                                         ins->klass = constrained_call;
8907                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8908                                         CHECK_CFG_EXCEPTION;
8909                                 } else if (!constrained_call->valuetype) {
8910                                         int dreg = alloc_ireg_ref (cfg);
8911
8912                                         /*
8913                                          * The type parameter is instantiated as a reference
8914                                          * type.  We have a managed pointer on the stack, so
8915                                          * we need to dereference it here.
8916                                          */
8917                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8918                                         ins->type = STACK_OBJ;
8919                                         sp [0] = ins;
8920                                 } else {
8921                                         if (cmethod->klass->valuetype) {
8922                                                 /* Own method */
8923                                         } else {
8924                                                 /* Interface method */
8925                                                 int ioffset, slot;
8926
8927                                                 mono_class_setup_vtable (constrained_call);
8928                                                 CHECK_TYPELOAD (constrained_call);
8929                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8930                                                 if (ioffset == -1)
8931                                                         TYPE_LOAD_ERROR (constrained_call);
8932                                                 slot = mono_method_get_vtable_slot (cmethod);
8933                                                 if (slot == -1)
8934                                                         TYPE_LOAD_ERROR (cmethod->klass);
8935                                                 cmethod = constrained_call->vtable [ioffset + slot];
8936
8937                                                 if (cmethod->klass == mono_defaults.enum_class) {
8938                                                         /* Enum implements some interfaces, so treat this as the first case */
8939                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8940                                                         ins->klass = constrained_call;
8941                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8942                                                         CHECK_CFG_EXCEPTION;
8943                                                 }
8944                                         }
8945                                         virtual = 0;
8946                                 }
8947                                 constrained_call = NULL;
8948                         }
8949
8950                         if (!calli && check_call_signature (cfg, fsig, sp))
8951                                 UNVERIFIED;
8952
8953 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8954                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8955                                 delegate_invoke = TRUE;
8956 #endif
8957
8958                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8959                                 bblock = cfg->cbb;
8960                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8961                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8962                                         emit_widen = FALSE;
8963                                 }
8964
8965                                 goto call_end;
8966                         }
8967
8968                         /* 
8969                          * If the callee is a shared method, then its static cctor
8970                          * might not get called after the call was patched.
8971                          */
8972                         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)) {
8973                                 emit_generic_class_init (cfg, cmethod->klass);
8974                                 CHECK_TYPELOAD (cmethod->klass);
8975                         }
8976
8977                         if (cmethod)
8978                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8979
8980                         if (cfg->generic_sharing_context && cmethod) {
8981                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8982
8983                                 context_used = mini_method_check_context_used (cfg, cmethod);
8984
8985                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8986                                         /* Generic method interface
8987                                            calls are resolved via a
8988                                            helper function and don't
8989                                            need an imt. */
8990                                         if (!cmethod_context || !cmethod_context->method_inst)
8991                                                 pass_imt_from_rgctx = TRUE;
8992                                 }
8993
8994                                 /*
8995                                  * If a shared method calls another
8996                                  * shared method then the caller must
8997                                  * have a generic sharing context
8998                                  * because the magic trampoline
8999                                  * requires it.  FIXME: We shouldn't
9000                                  * have to force the vtable/mrgctx
9001                                  * variable here.  Instead there
9002                                  * should be a flag in the cfg to
9003                                  * request a generic sharing context.
9004                                  */
9005                                 if (context_used &&
9006                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9007                                         mono_get_vtable_var (cfg);
9008                         }
9009
9010                         if (pass_vtable) {
9011                                 if (context_used) {
9012                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9013                                 } else {
9014                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9015
9016                                         CHECK_TYPELOAD (cmethod->klass);
9017                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9018                                 }
9019                         }
9020
9021                         if (pass_mrgctx) {
9022                                 g_assert (!vtable_arg);
9023
9024                                 if (!cfg->compile_aot) {
9025                                         /* 
9026                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9027                                          * for type load errors before.
9028                                          */
9029                                         mono_class_setup_vtable (cmethod->klass);
9030                                         CHECK_TYPELOAD (cmethod->klass);
9031                                 }
9032
9033                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9034
9035                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9036                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9037                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9038                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9039                                         if (virtual)
9040                                                 check_this = TRUE;
9041                                         virtual = 0;
9042                                 }
9043                         }
9044
9045                         if (pass_imt_from_rgctx) {
9046                                 g_assert (!pass_vtable);
9047                                 g_assert (cmethod);
9048
9049                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9050                                         cmethod, MONO_RGCTX_INFO_METHOD);
9051                         }
9052
9053                         if (check_this)
9054                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9055
9056                         /* Calling virtual generic methods */
9057                         if (cmethod && virtual && 
9058                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9059                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9060                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9061                             fsig->generic_param_count && 
9062                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9063                                 MonoInst *this_temp, *this_arg_temp, *store;
9064                                 MonoInst *iargs [4];
9065                                 gboolean use_imt = FALSE;
9066
9067                                 g_assert (fsig->is_inflated);
9068
9069                                 /* Prevent inlining of methods that contain indirect calls */
9070                                 INLINE_FAILURE ("virtual generic call");
9071
9072                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9073                                         GSHAREDVT_FAILURE (*ip);
9074
9075 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9076                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
9077                                         use_imt = TRUE;
9078 #endif
9079
9080                                 if (use_imt) {
9081                                         g_assert (!imt_arg);
9082                                         if (!context_used)
9083                                                 g_assert (cmethod->is_inflated);
9084                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9085                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9086                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9087                                 } else {
9088                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9089                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9090                                         MONO_ADD_INS (bblock, store);
9091
9092                                         /* FIXME: This should be a managed pointer */
9093                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9094
9095                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9096                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9097                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9098                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9099                                         addr = mono_emit_jit_icall (cfg,
9100                                                                                                 mono_helper_compile_generic_method, iargs);
9101
9102                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9103
9104                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9105                                 }
9106
9107                                 goto call_end;
9108                         }
9109
9110                         /*
9111                          * Implement a workaround for the inherent races involved in locking:
9112                          * Monitor.Enter ()
9113                          * try {
9114                          * } finally {
9115                          *    Monitor.Exit ()
9116                          * }
9117                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9118                          * try block, the Exit () won't be executed, see:
9119                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9120                          * To work around this, we extend such try blocks to include the last x bytes
9121                          * of the Monitor.Enter () call.
9122                          */
9123                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9124                                 MonoBasicBlock *tbb;
9125
9126                                 GET_BBLOCK (cfg, tbb, ip + 5);
9127                                 /* 
9128                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9129                                  * from Monitor.Enter like ArgumentNullException.
9130                                  */
9131                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9132                                         /* Mark this bblock as needing to be extended */
9133                                         tbb->extend_try_block = TRUE;
9134                                 }
9135                         }
9136
9137                         /* Conversion to a JIT intrinsic */
9138                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9139                                 bblock = cfg->cbb;
9140                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9141                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9142                                         emit_widen = FALSE;
9143                                 }
9144                                 goto call_end;
9145                         }
9146
9147                         /* Inlining */
9148                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
9149                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9150                             mono_method_check_inlining (cfg, cmethod)) {
9151                                 int costs;
9152                                 gboolean always = FALSE;
9153
9154                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9155                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9156                                         /* Prevent inlining of methods that call wrappers */
9157                                         INLINE_FAILURE ("wrapper call");
9158                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9159                                         always = TRUE;
9160                                 }
9161
9162                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
9163                                 if (costs) {
9164                                         cfg->real_offset += 5;
9165
9166                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9167                                                 /* *sp is already set by inline_method */
9168                                                 sp++;
9169                                                 push_res = FALSE;
9170                                         }
9171
9172                                         inline_costs += costs;
9173
9174                                         goto call_end;
9175                                 }
9176                         }
9177
9178                         /* Tail recursion elimination */
9179                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9180                                 gboolean has_vtargs = FALSE;
9181                                 int i;
9182
9183                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9184                                 INLINE_FAILURE ("tail call");
9185
9186                                 /* keep it simple */
9187                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9188                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9189                                                 has_vtargs = TRUE;
9190                                 }
9191
9192                                 if (!has_vtargs) {
9193                                         for (i = 0; i < n; ++i)
9194                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9195                                         MONO_INST_NEW (cfg, ins, OP_BR);
9196                                         MONO_ADD_INS (bblock, ins);
9197                                         tblock = start_bblock->out_bb [0];
9198                                         link_bblock (cfg, bblock, tblock);
9199                                         ins->inst_target_bb = tblock;
9200                                         start_new_bblock = 1;
9201
9202                                         /* skip the CEE_RET, too */
9203                                         if (ip_in_bb (cfg, bblock, ip + 5))
9204                                                 skip_ret = TRUE;
9205                                         push_res = FALSE;
9206                                         goto call_end;
9207                                 }
9208                         }
9209
9210                         inline_costs += 10 * num_calls++;
9211
9212                         /*
9213                          * Making generic calls out of gsharedvt methods.
9214                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9215                          * patching gshared method addresses into a gsharedvt method.
9216                          */
9217                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9218                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9219                                 MonoRgctxInfoType info_type;
9220
9221                                 if (virtual) {
9222                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9223                                                 //GSHAREDVT_FAILURE (*ip);
9224                                         // disable for possible remoting calls
9225                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9226                                                 GSHAREDVT_FAILURE (*ip);
9227                                         if (fsig->generic_param_count) {
9228                                                 /* virtual generic call */
9229                                                 g_assert (mono_use_imt);
9230                                                 g_assert (!imt_arg);
9231                                                 /* Same as the virtual generic case above */
9232                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9233                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9234                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9235                                                 vtable_arg = NULL;
9236                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9237                                                 /* This can happen when we call a fully instantiated iface method */
9238                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9239                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9240                                                 vtable_arg = NULL;
9241                                         }
9242                                 }
9243
9244                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9245                                         keep_this_alive = sp [0];
9246
9247                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9248                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9249                                 else
9250                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9251                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9252
9253                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9254                                 goto call_end;
9255                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9256                                 /*
9257                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9258                                  */
9259                                 MonoInst *callee = addr;
9260
9261                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9262                                         /* Not tested */
9263                                         GSHAREDVT_FAILURE (*ip);
9264
9265                                 addr = emit_get_rgctx_sig (cfg, context_used,
9266                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9267                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9268                                 goto call_end;
9269                         }
9270
9271                         /* Generic sharing */
9272
9273                         /*
9274                          * Use this if the callee is gsharedvt sharable too, since
9275                          * at runtime we might find an instantiation so the call cannot
9276                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9277                          */
9278                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9279                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9280                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9281                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9282                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9283                                 INLINE_FAILURE ("gshared");
9284
9285                                 g_assert (cfg->generic_sharing_context && cmethod);
9286                                 g_assert (!addr);
9287
9288                                 /*
9289                                  * We are compiling a call to a
9290                                  * generic method from shared code,
9291                                  * which means that we have to look up
9292                                  * the method in the rgctx and do an
9293                                  * indirect call.
9294                                  */
9295                                 if (fsig->hasthis)
9296                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9297
9298                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9299                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9300                                 goto call_end;
9301                         }
9302
9303                         /* Indirect calls */
9304                         if (addr) {
9305                                 if (call_opcode == CEE_CALL)
9306                                         g_assert (context_used);
9307                                 else if (call_opcode == CEE_CALLI)
9308                                         g_assert (!vtable_arg);
9309                                 else
9310                                         /* FIXME: what the hell is this??? */
9311                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
9312                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
9313
9314                                 /* Prevent inlining of methods with indirect calls */
9315                                 INLINE_FAILURE ("indirect call");
9316
9317                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9318                                         int info_type;
9319                                         gpointer info_data;
9320
9321                                         /* 
9322                                          * Instead of emitting an indirect call, emit a direct call
9323                                          * with the contents of the aotconst as the patch info.
9324                                          */
9325                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9326                                                 info_type = addr->inst_c1;
9327                                                 info_data = addr->inst_p0;
9328                                         } else {
9329                                                 info_type = addr->inst_right->inst_c1;
9330                                                 info_data = addr->inst_right->inst_left;
9331                                         }
9332                                         
9333                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9334                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9335                                                 NULLIFY_INS (addr);
9336                                                 goto call_end;
9337                                         }
9338                                 }
9339                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9340                                 goto call_end;
9341                         }
9342                                         
9343                         /* Array methods */
9344                         if (array_rank) {
9345                                 MonoInst *addr;
9346
9347                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9348                                         MonoInst *val = sp [fsig->param_count];
9349
9350                                         if (val->type == STACK_OBJ) {
9351                                                 MonoInst *iargs [2];
9352
9353                                                 iargs [0] = sp [0];
9354                                                 iargs [1] = val;
9355                                                 
9356                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9357                                         }
9358                                         
9359                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9360                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9361                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9362                                                 emit_write_barrier (cfg, addr, val);
9363                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9364                                                 GSHAREDVT_FAILURE (*ip);
9365                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9366                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9367
9368                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9369                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9370                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9371                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9372                                         CHECK_TYPELOAD (cmethod->klass);
9373                                         
9374                                         readonly = FALSE;
9375                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9376                                         ins = addr;
9377                                 } else {
9378                                         g_assert_not_reached ();
9379                                 }
9380
9381                                 emit_widen = FALSE;
9382                                 goto call_end;
9383                         }
9384
9385                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9386                         if (ins)
9387                                 goto call_end;
9388
9389                         /* Tail prefix / tail call optimization */
9390
9391                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9392                         /* FIXME: runtime generic context pointer for jumps? */
9393                         /* FIXME: handle this for generic sharing eventually */
9394                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
9395                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9396                                 supported_tail_call = TRUE;
9397
9398                         if (supported_tail_call) {
9399                                 MonoCallInst *call;
9400
9401                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9402                                 INLINE_FAILURE ("tail call");
9403
9404                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9405
9406                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9407                                         /* Handle tail calls similarly to normal calls */
9408                                         tail_call = TRUE;
9409                                 } else {
9410                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9411
9412                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9413                                         call->tail_call = TRUE;
9414                                         call->method = cmethod;
9415                                         call->signature = mono_method_signature (cmethod);
9416
9417                                         /*
9418                                          * We implement tail calls by storing the actual arguments into the 
9419                                          * argument variables, then emitting a CEE_JMP.
9420                                          */
9421                                         for (i = 0; i < n; ++i) {
9422                                                 /* Prevent argument from being register allocated */
9423                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9424                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9425                                         }
9426                                         ins = (MonoInst*)call;
9427                                         ins->inst_p0 = cmethod;
9428                                         ins->inst_p1 = arg_array [0];
9429                                         MONO_ADD_INS (bblock, ins);
9430                                         link_bblock (cfg, bblock, end_bblock);                  
9431                                         start_new_bblock = 1;
9432
9433                                         // FIXME: Eliminate unreachable epilogs
9434
9435                                         /*
9436                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9437                                          * only reachable from this call.
9438                                          */
9439                                         GET_BBLOCK (cfg, tblock, ip + 5);
9440                                         if (tblock == bblock || tblock->in_count == 0)
9441                                                 skip_ret = TRUE;
9442                                         push_res = FALSE;
9443
9444                                         goto call_end;
9445                                 }
9446                         }
9447
9448                         /* 
9449                          * Synchronized wrappers.
9450                          * Its hard to determine where to replace a method with its synchronized
9451                          * wrapper without causing an infinite recursion. The current solution is
9452                          * to add the synchronized wrapper in the trampolines, and to
9453                          * change the called method to a dummy wrapper, and resolve that wrapper
9454                          * to the real method in mono_jit_compile_method ().
9455                          */
9456                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9457                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9458                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9459                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9460                         }
9461
9462                         /* Common call */
9463                         INLINE_FAILURE ("call");
9464                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9465                                                                                           imt_arg, vtable_arg);
9466
9467                         if (tail_call) {
9468                                 link_bblock (cfg, bblock, end_bblock);                  
9469                                 start_new_bblock = 1;
9470
9471                                 // FIXME: Eliminate unreachable epilogs
9472
9473                                 /*
9474                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9475                                  * only reachable from this call.
9476                                  */
9477                                 GET_BBLOCK (cfg, tblock, ip + 5);
9478                                 if (tblock == bblock || tblock->in_count == 0)
9479                                         skip_ret = TRUE;
9480                                 push_res = FALSE;
9481                         }
9482
9483                         call_end:
9484
9485                         /* End of call, INS should contain the result of the call, if any */
9486
9487                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9488                                 g_assert (ins);
9489                                 if (emit_widen)
9490                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9491                                 else
9492                                         *sp++ = ins;
9493                         }
9494
9495                         if (keep_this_alive) {
9496                                 MonoInst *dummy_use;
9497
9498                                 /* See mono_emit_method_call_full () */
9499                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9500                         }
9501
9502                         CHECK_CFG_EXCEPTION;
9503
9504                         ip += 5;
9505                         if (skip_ret) {
9506                                 g_assert (*ip == CEE_RET);
9507                                 ip += 1;
9508                         }
9509                         ins_flag = 0;
9510                         constrained_call = NULL;
9511                         if (need_seq_point)
9512                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9513                         break;
9514                 }
9515                 case CEE_RET:
9516                         if (cfg->method != method) {
9517                                 /* return from inlined method */
9518                                 /* 
9519                                  * If in_count == 0, that means the ret is unreachable due to
9520                                  * being preceeded by a throw. In that case, inline_method () will
9521                                  * handle setting the return value 
9522                                  * (test case: test_0_inline_throw ()).
9523                                  */
9524                                 if (return_var && cfg->cbb->in_count) {
9525                                         MonoType *ret_type = mono_method_signature (method)->ret;
9526
9527                                         MonoInst *store;
9528                                         CHECK_STACK (1);
9529                                         --sp;
9530
9531                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9532                                                 UNVERIFIED;
9533
9534                                         //g_assert (returnvar != -1);
9535                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9536                                         cfg->ret_var_set = TRUE;
9537                                 } 
9538                         } else {
9539                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9540
9541                                 if (cfg->lmf_var && cfg->cbb->in_count)
9542                                         emit_pop_lmf (cfg);
9543
9544                                 if (cfg->ret) {
9545                                         MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
9546
9547                                         if (seq_points && !sym_seq_points) {
9548                                                 /* 
9549                                                  * Place a seq point here too even through the IL stack is not
9550                                                  * empty, so a step over on
9551                                                  * call <FOO>
9552                                                  * ret
9553                                                  * will work correctly.
9554                                                  */
9555                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9556                                                 MONO_ADD_INS (cfg->cbb, ins);
9557                                         }
9558
9559                                         g_assert (!return_var);
9560                                         CHECK_STACK (1);
9561                                         --sp;
9562
9563                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9564                                                 UNVERIFIED;
9565
9566                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9567                                                 MonoInst *ret_addr;
9568
9569                                                 if (!cfg->vret_addr) {
9570                                                         MonoInst *ins;
9571
9572                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9573                                                 } else {
9574                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9575
9576                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9577                                                         ins->klass = mono_class_from_mono_type (ret_type);
9578                                                 }
9579                                         } else {
9580 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9581                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9582                                                         MonoInst *iargs [1];
9583                                                         MonoInst *conv;
9584
9585                                                         iargs [0] = *sp;
9586                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9587                                                         mono_arch_emit_setret (cfg, method, conv);
9588                                                 } else {
9589                                                         mono_arch_emit_setret (cfg, method, *sp);
9590                                                 }
9591 #else
9592                                                 mono_arch_emit_setret (cfg, method, *sp);
9593 #endif
9594                                         }
9595                                 }
9596                         }
9597                         if (sp != stack_start)
9598                                 UNVERIFIED;
9599                         MONO_INST_NEW (cfg, ins, OP_BR);
9600                         ip++;
9601                         ins->inst_target_bb = end_bblock;
9602                         MONO_ADD_INS (bblock, ins);
9603                         link_bblock (cfg, bblock, end_bblock);
9604                         start_new_bblock = 1;
9605                         break;
9606                 case CEE_BR_S:
9607                         CHECK_OPSIZE (2);
9608                         MONO_INST_NEW (cfg, ins, OP_BR);
9609                         ip++;
9610                         target = ip + 1 + (signed char)(*ip);
9611                         ++ip;
9612                         GET_BBLOCK (cfg, tblock, target);
9613                         link_bblock (cfg, bblock, tblock);
9614                         ins->inst_target_bb = tblock;
9615                         if (sp != stack_start) {
9616                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9617                                 sp = stack_start;
9618                                 CHECK_UNVERIFIABLE (cfg);
9619                         }
9620                         MONO_ADD_INS (bblock, ins);
9621                         start_new_bblock = 1;
9622                         inline_costs += BRANCH_COST;
9623                         break;
9624                 case CEE_BEQ_S:
9625                 case CEE_BGE_S:
9626                 case CEE_BGT_S:
9627                 case CEE_BLE_S:
9628                 case CEE_BLT_S:
9629                 case CEE_BNE_UN_S:
9630                 case CEE_BGE_UN_S:
9631                 case CEE_BGT_UN_S:
9632                 case CEE_BLE_UN_S:
9633                 case CEE_BLT_UN_S:
9634                         CHECK_OPSIZE (2);
9635                         CHECK_STACK (2);
9636                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9637                         ip++;
9638                         target = ip + 1 + *(signed char*)ip;
9639                         ip++;
9640
9641                         ADD_BINCOND (NULL);
9642
9643                         sp = stack_start;
9644                         inline_costs += BRANCH_COST;
9645                         break;
9646                 case CEE_BR:
9647                         CHECK_OPSIZE (5);
9648                         MONO_INST_NEW (cfg, ins, OP_BR);
9649                         ip++;
9650
9651                         target = ip + 4 + (gint32)read32(ip);
9652                         ip += 4;
9653                         GET_BBLOCK (cfg, tblock, target);
9654                         link_bblock (cfg, bblock, tblock);
9655                         ins->inst_target_bb = tblock;
9656                         if (sp != stack_start) {
9657                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9658                                 sp = stack_start;
9659                                 CHECK_UNVERIFIABLE (cfg);
9660                         }
9661
9662                         MONO_ADD_INS (bblock, ins);
9663
9664                         start_new_bblock = 1;
9665                         inline_costs += BRANCH_COST;
9666                         break;
9667                 case CEE_BRFALSE_S:
9668                 case CEE_BRTRUE_S:
9669                 case CEE_BRFALSE:
9670                 case CEE_BRTRUE: {
9671                         MonoInst *cmp;
9672                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9673                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9674                         guint32 opsize = is_short ? 1 : 4;
9675
9676                         CHECK_OPSIZE (opsize);
9677                         CHECK_STACK (1);
9678                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9679                                 UNVERIFIED;
9680                         ip ++;
9681                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9682                         ip += opsize;
9683
9684                         sp--;
9685
9686                         GET_BBLOCK (cfg, tblock, target);
9687                         link_bblock (cfg, bblock, tblock);
9688                         GET_BBLOCK (cfg, tblock, ip);
9689                         link_bblock (cfg, bblock, tblock);
9690
9691                         if (sp != stack_start) {
9692                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9693                                 CHECK_UNVERIFIABLE (cfg);
9694                         }
9695
9696                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9697                         cmp->sreg1 = sp [0]->dreg;
9698                         type_from_op (cfg, cmp, sp [0], NULL);
9699                         CHECK_TYPE (cmp);
9700
9701 #if SIZEOF_REGISTER == 4
9702                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9703                                 /* Convert it to OP_LCOMPARE */
9704                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9705                                 ins->type = STACK_I8;
9706                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9707                                 ins->inst_l = 0;
9708                                 MONO_ADD_INS (bblock, ins);
9709                                 cmp->opcode = OP_LCOMPARE;
9710                                 cmp->sreg2 = ins->dreg;
9711                         }
9712 #endif
9713                         MONO_ADD_INS (bblock, cmp);
9714
9715                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9716                         type_from_op (cfg, ins, sp [0], NULL);
9717                         MONO_ADD_INS (bblock, ins);
9718                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9719                         GET_BBLOCK (cfg, tblock, target);
9720                         ins->inst_true_bb = tblock;
9721                         GET_BBLOCK (cfg, tblock, ip);
9722                         ins->inst_false_bb = tblock;
9723                         start_new_bblock = 2;
9724
9725                         sp = stack_start;
9726                         inline_costs += BRANCH_COST;
9727                         break;
9728                 }
9729                 case CEE_BEQ:
9730                 case CEE_BGE:
9731                 case CEE_BGT:
9732                 case CEE_BLE:
9733                 case CEE_BLT:
9734                 case CEE_BNE_UN:
9735                 case CEE_BGE_UN:
9736                 case CEE_BGT_UN:
9737                 case CEE_BLE_UN:
9738                 case CEE_BLT_UN:
9739                         CHECK_OPSIZE (5);
9740                         CHECK_STACK (2);
9741                         MONO_INST_NEW (cfg, ins, *ip);
9742                         ip++;
9743                         target = ip + 4 + (gint32)read32(ip);
9744                         ip += 4;
9745
9746                         ADD_BINCOND (NULL);
9747
9748                         sp = stack_start;
9749                         inline_costs += BRANCH_COST;
9750                         break;
9751                 case CEE_SWITCH: {
9752                         MonoInst *src1;
9753                         MonoBasicBlock **targets;
9754                         MonoBasicBlock *default_bblock;
9755                         MonoJumpInfoBBTable *table;
9756                         int offset_reg = alloc_preg (cfg);
9757                         int target_reg = alloc_preg (cfg);
9758                         int table_reg = alloc_preg (cfg);
9759                         int sum_reg = alloc_preg (cfg);
9760                         gboolean use_op_switch;
9761
9762                         CHECK_OPSIZE (5);
9763                         CHECK_STACK (1);
9764                         n = read32 (ip + 1);
9765                         --sp;
9766                         src1 = sp [0];
9767                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9768                                 UNVERIFIED;
9769
9770                         ip += 5;
9771                         CHECK_OPSIZE (n * sizeof (guint32));
9772                         target = ip + n * sizeof (guint32);
9773
9774                         GET_BBLOCK (cfg, default_bblock, target);
9775                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9776
9777                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9778                         for (i = 0; i < n; ++i) {
9779                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9780                                 targets [i] = tblock;
9781                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9782                                 ip += 4;
9783                         }
9784
9785                         if (sp != stack_start) {
9786                                 /* 
9787                                  * Link the current bb with the targets as well, so handle_stack_args
9788                                  * will set their in_stack correctly.
9789                                  */
9790                                 link_bblock (cfg, bblock, default_bblock);
9791                                 for (i = 0; i < n; ++i)
9792                                         link_bblock (cfg, bblock, targets [i]);
9793
9794                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9795                                 sp = stack_start;
9796                                 CHECK_UNVERIFIABLE (cfg);
9797                         }
9798
9799                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9800                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9801                         bblock = cfg->cbb;
9802
9803                         for (i = 0; i < n; ++i)
9804                                 link_bblock (cfg, bblock, targets [i]);
9805
9806                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9807                         table->table = targets;
9808                         table->table_size = n;
9809
9810                         use_op_switch = FALSE;
9811 #ifdef TARGET_ARM
9812                         /* ARM implements SWITCH statements differently */
9813                         /* FIXME: Make it use the generic implementation */
9814                         if (!cfg->compile_aot)
9815                                 use_op_switch = TRUE;
9816 #endif
9817
9818                         if (COMPILE_LLVM (cfg))
9819                                 use_op_switch = TRUE;
9820
9821                         cfg->cbb->has_jump_table = 1;
9822
9823                         if (use_op_switch) {
9824                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9825                                 ins->sreg1 = src1->dreg;
9826                                 ins->inst_p0 = table;
9827                                 ins->inst_many_bb = targets;
9828                                 ins->klass = GUINT_TO_POINTER (n);
9829                                 MONO_ADD_INS (cfg->cbb, ins);
9830                         } else {
9831                                 if (sizeof (gpointer) == 8)
9832                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9833                                 else
9834                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9835
9836 #if SIZEOF_REGISTER == 8
9837                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9838                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9839 #endif
9840
9841                                 if (cfg->compile_aot) {
9842                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9843                                 } else {
9844                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9845                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9846                                         ins->inst_p0 = table;
9847                                         ins->dreg = table_reg;
9848                                         MONO_ADD_INS (cfg->cbb, ins);
9849                                 }
9850
9851                                 /* FIXME: Use load_memindex */
9852                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9853                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9854                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9855                         }
9856                         start_new_bblock = 1;
9857                         inline_costs += (BRANCH_COST * 2);
9858                         break;
9859                 }
9860                 case CEE_LDIND_I1:
9861                 case CEE_LDIND_U1:
9862                 case CEE_LDIND_I2:
9863                 case CEE_LDIND_U2:
9864                 case CEE_LDIND_I4:
9865                 case CEE_LDIND_U4:
9866                 case CEE_LDIND_I8:
9867                 case CEE_LDIND_I:
9868                 case CEE_LDIND_R4:
9869                 case CEE_LDIND_R8:
9870                 case CEE_LDIND_REF:
9871                         CHECK_STACK (1);
9872                         --sp;
9873
9874                         switch (*ip) {
9875                         case CEE_LDIND_R4:
9876                         case CEE_LDIND_R8:
9877                                 dreg = alloc_freg (cfg);
9878                                 break;
9879                         case CEE_LDIND_I8:
9880                                 dreg = alloc_lreg (cfg);
9881                                 break;
9882                         case CEE_LDIND_REF:
9883                                 dreg = alloc_ireg_ref (cfg);
9884                                 break;
9885                         default:
9886                                 dreg = alloc_preg (cfg);
9887                         }
9888
9889                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9890                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9891                         if (*ip == CEE_LDIND_R4)
9892                                 ins->type = cfg->r4_stack_type;
9893                         ins->flags |= ins_flag;
9894                         MONO_ADD_INS (bblock, ins);
9895                         *sp++ = ins;
9896                         if (ins_flag & MONO_INST_VOLATILE) {
9897                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9898                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9899                         }
9900                         ins_flag = 0;
9901                         ++ip;
9902                         break;
9903                 case CEE_STIND_REF:
9904                 case CEE_STIND_I1:
9905                 case CEE_STIND_I2:
9906                 case CEE_STIND_I4:
9907                 case CEE_STIND_I8:
9908                 case CEE_STIND_R4:
9909                 case CEE_STIND_R8:
9910                 case CEE_STIND_I:
9911                         CHECK_STACK (2);
9912                         sp -= 2;
9913
9914                         if (ins_flag & MONO_INST_VOLATILE) {
9915                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9916                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9917                         }
9918
9919                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9920                         ins->flags |= ins_flag;
9921                         ins_flag = 0;
9922
9923                         MONO_ADD_INS (bblock, ins);
9924
9925                         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)))
9926                                 emit_write_barrier (cfg, sp [0], sp [1]);
9927
9928                         inline_costs += 1;
9929                         ++ip;
9930                         break;
9931
9932                 case CEE_MUL:
9933                         CHECK_STACK (2);
9934
9935                         MONO_INST_NEW (cfg, ins, (*ip));
9936                         sp -= 2;
9937                         ins->sreg1 = sp [0]->dreg;
9938                         ins->sreg2 = sp [1]->dreg;
9939                         type_from_op (cfg, ins, sp [0], sp [1]);
9940                         CHECK_TYPE (ins);
9941                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9942
9943                         /* Use the immediate opcodes if possible */
9944                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9945                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9946                                 if (imm_opcode != -1) {
9947                                         ins->opcode = imm_opcode;
9948                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9949                                         ins->sreg2 = -1;
9950
9951                                         NULLIFY_INS (sp [1]);
9952                                 }
9953                         }
9954
9955                         MONO_ADD_INS ((cfg)->cbb, (ins));
9956
9957                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
9958                         ip++;
9959                         break;
9960                 case CEE_ADD:
9961                 case CEE_SUB:
9962                 case CEE_DIV:
9963                 case CEE_DIV_UN:
9964                 case CEE_REM:
9965                 case CEE_REM_UN:
9966                 case CEE_AND:
9967                 case CEE_OR:
9968                 case CEE_XOR:
9969                 case CEE_SHL:
9970                 case CEE_SHR:
9971                 case CEE_SHR_UN:
9972                         CHECK_STACK (2);
9973
9974                         MONO_INST_NEW (cfg, ins, (*ip));
9975                         sp -= 2;
9976                         ins->sreg1 = sp [0]->dreg;
9977                         ins->sreg2 = sp [1]->dreg;
9978                         type_from_op (cfg, ins, sp [0], sp [1]);
9979                         CHECK_TYPE (ins);
9980                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9981                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9982
9983                         /* FIXME: Pass opcode to is_inst_imm */
9984
9985                         /* Use the immediate opcodes if possible */
9986                         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)) {
9987                                 int imm_opcode;
9988
9989                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9990 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9991                                 /* Keep emulated opcodes which are optimized away later */
9992                                 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) {
9993                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9994                                 }
9995 #endif
9996                                 if (imm_opcode != -1) {
9997                                         ins->opcode = imm_opcode;
9998                                         if (sp [1]->opcode == OP_I8CONST) {
9999 #if SIZEOF_REGISTER == 8
10000                                                 ins->inst_imm = sp [1]->inst_l;
10001 #else
10002                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10003                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10004 #endif
10005                                         }
10006                                         else
10007                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10008                                         ins->sreg2 = -1;
10009
10010                                         /* Might be followed by an instruction added by add_widen_op */
10011                                         if (sp [1]->next == NULL)
10012                                                 NULLIFY_INS (sp [1]);
10013                                 }
10014                         }
10015                         MONO_ADD_INS ((cfg)->cbb, (ins));
10016
10017                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10018                         ip++;
10019                         break;
10020                 case CEE_NEG:
10021                 case CEE_NOT:
10022                 case CEE_CONV_I1:
10023                 case CEE_CONV_I2:
10024                 case CEE_CONV_I4:
10025                 case CEE_CONV_R4:
10026                 case CEE_CONV_R8:
10027                 case CEE_CONV_U4:
10028                 case CEE_CONV_I8:
10029                 case CEE_CONV_U8:
10030                 case CEE_CONV_OVF_I8:
10031                 case CEE_CONV_OVF_U8:
10032                 case CEE_CONV_R_UN:
10033                         CHECK_STACK (1);
10034
10035                         /* Special case this earlier so we have long constants in the IR */
10036                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10037                                 int data = sp [-1]->inst_c0;
10038                                 sp [-1]->opcode = OP_I8CONST;
10039                                 sp [-1]->type = STACK_I8;
10040 #if SIZEOF_REGISTER == 8
10041                                 if ((*ip) == CEE_CONV_U8)
10042                                         sp [-1]->inst_c0 = (guint32)data;
10043                                 else
10044                                         sp [-1]->inst_c0 = data;
10045 #else
10046                                 sp [-1]->inst_ls_word = data;
10047                                 if ((*ip) == CEE_CONV_U8)
10048                                         sp [-1]->inst_ms_word = 0;
10049                                 else
10050                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10051 #endif
10052                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10053                         }
10054                         else {
10055                                 ADD_UNOP (*ip);
10056                         }
10057                         ip++;
10058                         break;
10059                 case CEE_CONV_OVF_I4:
10060                 case CEE_CONV_OVF_I1:
10061                 case CEE_CONV_OVF_I2:
10062                 case CEE_CONV_OVF_I:
10063                 case CEE_CONV_OVF_U:
10064                         CHECK_STACK (1);
10065
10066                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10067                                 ADD_UNOP (CEE_CONV_OVF_I8);
10068                                 ADD_UNOP (*ip);
10069                         } else {
10070                                 ADD_UNOP (*ip);
10071                         }
10072                         ip++;
10073                         break;
10074                 case CEE_CONV_OVF_U1:
10075                 case CEE_CONV_OVF_U2:
10076                 case CEE_CONV_OVF_U4:
10077                         CHECK_STACK (1);
10078
10079                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10080                                 ADD_UNOP (CEE_CONV_OVF_U8);
10081                                 ADD_UNOP (*ip);
10082                         } else {
10083                                 ADD_UNOP (*ip);
10084                         }
10085                         ip++;
10086                         break;
10087                 case CEE_CONV_OVF_I1_UN:
10088                 case CEE_CONV_OVF_I2_UN:
10089                 case CEE_CONV_OVF_I4_UN:
10090                 case CEE_CONV_OVF_I8_UN:
10091                 case CEE_CONV_OVF_U1_UN:
10092                 case CEE_CONV_OVF_U2_UN:
10093                 case CEE_CONV_OVF_U4_UN:
10094                 case CEE_CONV_OVF_U8_UN:
10095                 case CEE_CONV_OVF_I_UN:
10096                 case CEE_CONV_OVF_U_UN:
10097                 case CEE_CONV_U2:
10098                 case CEE_CONV_U1:
10099                 case CEE_CONV_I:
10100                 case CEE_CONV_U:
10101                         CHECK_STACK (1);
10102                         ADD_UNOP (*ip);
10103                         CHECK_CFG_EXCEPTION;
10104                         ip++;
10105                         break;
10106                 case CEE_ADD_OVF:
10107                 case CEE_ADD_OVF_UN:
10108                 case CEE_MUL_OVF:
10109                 case CEE_MUL_OVF_UN:
10110                 case CEE_SUB_OVF:
10111                 case CEE_SUB_OVF_UN:
10112                         CHECK_STACK (2);
10113                         ADD_BINOP (*ip);
10114                         ip++;
10115                         break;
10116                 case CEE_CPOBJ:
10117                         GSHAREDVT_FAILURE (*ip);
10118                         CHECK_OPSIZE (5);
10119                         CHECK_STACK (2);
10120                         token = read32 (ip + 1);
10121                         klass = mini_get_class (method, token, generic_context);
10122                         CHECK_TYPELOAD (klass);
10123                         sp -= 2;
10124                         if (generic_class_is_reference_type (cfg, klass)) {
10125                                 MonoInst *store, *load;
10126                                 int dreg = alloc_ireg_ref (cfg);
10127
10128                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10129                                 load->flags |= ins_flag;
10130                                 MONO_ADD_INS (cfg->cbb, load);
10131
10132                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10133                                 store->flags |= ins_flag;
10134                                 MONO_ADD_INS (cfg->cbb, store);
10135
10136                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10137                                         emit_write_barrier (cfg, sp [0], sp [1]);
10138                         } else {
10139                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10140                         }
10141                         ins_flag = 0;
10142                         ip += 5;
10143                         break;
10144                 case CEE_LDOBJ: {
10145                         int loc_index = -1;
10146                         int stloc_len = 0;
10147
10148                         CHECK_OPSIZE (5);
10149                         CHECK_STACK (1);
10150                         --sp;
10151                         token = read32 (ip + 1);
10152                         klass = mini_get_class (method, token, generic_context);
10153                         CHECK_TYPELOAD (klass);
10154
10155                         /* Optimize the common ldobj+stloc combination */
10156                         switch (ip [5]) {
10157                         case CEE_STLOC_S:
10158                                 loc_index = ip [6];
10159                                 stloc_len = 2;
10160                                 break;
10161                         case CEE_STLOC_0:
10162                         case CEE_STLOC_1:
10163                         case CEE_STLOC_2:
10164                         case CEE_STLOC_3:
10165                                 loc_index = ip [5] - CEE_STLOC_0;
10166                                 stloc_len = 1;
10167                                 break;
10168                         default:
10169                                 break;
10170                         }
10171
10172                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
10173                                 CHECK_LOCAL (loc_index);
10174
10175                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10176                                 ins->dreg = cfg->locals [loc_index]->dreg;
10177                                 ins->flags |= ins_flag;
10178                                 ip += 5;
10179                                 ip += stloc_len;
10180                                 if (ins_flag & MONO_INST_VOLATILE) {
10181                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10182                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10183                                 }
10184                                 ins_flag = 0;
10185                                 break;
10186                         }
10187
10188                         /* Optimize the ldobj+stobj combination */
10189                         /* The reference case ends up being a load+store anyway */
10190                         /* Skip this if the operation is volatile. */
10191                         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)) {
10192                                 CHECK_STACK (1);
10193
10194                                 sp --;
10195
10196                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10197
10198                                 ip += 5 + 5;
10199                                 ins_flag = 0;
10200                                 break;
10201                         }
10202
10203                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10204                         ins->flags |= ins_flag;
10205                         *sp++ = ins;
10206
10207                         if (ins_flag & MONO_INST_VOLATILE) {
10208                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10209                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10210                         }
10211
10212                         ip += 5;
10213                         ins_flag = 0;
10214                         inline_costs += 1;
10215                         break;
10216                 }
10217                 case CEE_LDSTR:
10218                         CHECK_STACK_OVF (1);
10219                         CHECK_OPSIZE (5);
10220                         n = read32 (ip + 1);
10221
10222                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10223                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10224                                 ins->type = STACK_OBJ;
10225                                 *sp = ins;
10226                         }
10227                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10228                                 MonoInst *iargs [1];
10229                                 char *str = mono_method_get_wrapper_data (method, n);
10230
10231                                 if (cfg->compile_aot)
10232                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10233                                 else
10234                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10235                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10236                         } else {
10237                                 if (cfg->opt & MONO_OPT_SHARED) {
10238                                         MonoInst *iargs [3];
10239
10240                                         if (cfg->compile_aot) {
10241                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10242                                         }
10243                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10244                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10245                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10246                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10247                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10248                                 } else {
10249                                         if (bblock->out_of_line) {
10250                                                 MonoInst *iargs [2];
10251
10252                                                 if (image == mono_defaults.corlib) {
10253                                                         /* 
10254                                                          * Avoid relocations in AOT and save some space by using a 
10255                                                          * version of helper_ldstr specialized to mscorlib.
10256                                                          */
10257                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10258                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10259                                                 } else {
10260                                                         /* Avoid creating the string object */
10261                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10262                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10263                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10264                                                 }
10265                                         } 
10266                                         else
10267                                         if (cfg->compile_aot) {
10268                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10269                                                 *sp = ins;
10270                                                 MONO_ADD_INS (bblock, ins);
10271                                         } 
10272                                         else {
10273                                                 NEW_PCONST (cfg, ins, NULL);
10274                                                 ins->type = STACK_OBJ;
10275                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10276                                                 if (!ins->inst_p0)
10277                                                         OUT_OF_MEMORY_FAILURE;
10278
10279                                                 *sp = ins;
10280                                                 MONO_ADD_INS (bblock, ins);
10281                                         }
10282                                 }
10283                         }
10284
10285                         sp++;
10286                         ip += 5;
10287                         break;
10288                 case CEE_NEWOBJ: {
10289                         MonoInst *iargs [2];
10290                         MonoMethodSignature *fsig;
10291                         MonoInst this_ins;
10292                         MonoInst *alloc;
10293                         MonoInst *vtable_arg = NULL;
10294
10295                         CHECK_OPSIZE (5);
10296                         token = read32 (ip + 1);
10297                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10298                         if (!cmethod || mono_loader_get_last_error ())
10299                                 LOAD_ERROR;
10300                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10301                         CHECK_CFG_ERROR;
10302
10303                         mono_save_token_info (cfg, image, token, cmethod);
10304
10305                         if (!mono_class_init (cmethod->klass))
10306                                 TYPE_LOAD_ERROR (cmethod->klass);
10307
10308                         context_used = mini_method_check_context_used (cfg, cmethod);
10309
10310                         if (mono_security_cas_enabled ()) {
10311                                 if (check_linkdemand (cfg, method, cmethod))
10312                                         INLINE_FAILURE ("linkdemand");
10313                                 CHECK_CFG_EXCEPTION;
10314                         } else if (mono_security_core_clr_enabled ()) {
10315                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10316                         }
10317
10318                         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)) {
10319                                 emit_generic_class_init (cfg, cmethod->klass);
10320                                 CHECK_TYPELOAD (cmethod->klass);
10321                         }
10322
10323                         /*
10324                         if (cfg->gsharedvt) {
10325                                 if (mini_is_gsharedvt_variable_signature (sig))
10326                                         GSHAREDVT_FAILURE (*ip);
10327                         }
10328                         */
10329
10330                         n = fsig->param_count;
10331                         CHECK_STACK (n);
10332
10333                         /* 
10334                          * Generate smaller code for the common newobj <exception> instruction in
10335                          * argument checking code.
10336                          */
10337                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10338                                 is_exception_class (cmethod->klass) && n <= 2 &&
10339                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10340                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10341                                 MonoInst *iargs [3];
10342
10343                                 sp -= n;
10344
10345                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10346                                 switch (n) {
10347                                 case 0:
10348                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10349                                         break;
10350                                 case 1:
10351                                         iargs [1] = sp [0];
10352                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10353                                         break;
10354                                 case 2:
10355                                         iargs [1] = sp [0];
10356                                         iargs [2] = sp [1];
10357                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10358                                         break;
10359                                 default:
10360                                         g_assert_not_reached ();
10361                                 }
10362
10363                                 ip += 5;
10364                                 inline_costs += 5;
10365                                 break;
10366                         }
10367
10368                         /* move the args to allow room for 'this' in the first position */
10369                         while (n--) {
10370                                 --sp;
10371                                 sp [1] = sp [0];
10372                         }
10373
10374                         /* check_call_signature () requires sp[0] to be set */
10375                         this_ins.type = STACK_OBJ;
10376                         sp [0] = &this_ins;
10377                         if (check_call_signature (cfg, fsig, sp))
10378                                 UNVERIFIED;
10379
10380                         iargs [0] = NULL;
10381
10382                         if (mini_class_is_system_array (cmethod->klass)) {
10383                                 *sp = emit_get_rgctx_method (cfg, context_used,
10384                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10385
10386                                 /* Avoid varargs in the common case */
10387                                 if (fsig->param_count == 1)
10388                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10389                                 else if (fsig->param_count == 2)
10390                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10391                                 else if (fsig->param_count == 3)
10392                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10393                                 else if (fsig->param_count == 4)
10394                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10395                                 else
10396                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10397                         } else if (cmethod->string_ctor) {
10398                                 g_assert (!context_used);
10399                                 g_assert (!vtable_arg);
10400                                 /* we simply pass a null pointer */
10401                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10402                                 /* now call the string ctor */
10403                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10404                         } else {
10405                                 if (cmethod->klass->valuetype) {
10406                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10407                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10408                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10409
10410                                         alloc = NULL;
10411
10412                                         /* 
10413                                          * The code generated by mini_emit_virtual_call () expects
10414                                          * iargs [0] to be a boxed instance, but luckily the vcall
10415                                          * will be transformed into a normal call there.
10416                                          */
10417                                 } else if (context_used) {
10418                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10419                                         *sp = alloc;
10420                                 } else {
10421                                         MonoVTable *vtable = NULL;
10422
10423                                         if (!cfg->compile_aot)
10424                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10425                                         CHECK_TYPELOAD (cmethod->klass);
10426
10427                                         /*
10428                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10429                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10430                                          * As a workaround, we call class cctors before allocating objects.
10431                                          */
10432                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10433                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10434                                                 if (cfg->verbose_level > 2)
10435                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10436                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10437                                         }
10438
10439                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10440                                         *sp = alloc;
10441                                 }
10442                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10443
10444                                 if (alloc)
10445                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10446
10447                                 /* Now call the actual ctor */
10448                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10449                                 CHECK_CFG_EXCEPTION;
10450                         }
10451
10452                         if (alloc == NULL) {
10453                                 /* Valuetype */
10454                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10455                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10456                                 *sp++= ins;
10457                         } else {
10458                                 *sp++ = alloc;
10459                         }
10460                         
10461                         ip += 5;
10462                         inline_costs += 5;
10463                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10464                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10465                         break;
10466                 }
10467                 case CEE_CASTCLASS:
10468                         CHECK_STACK (1);
10469                         --sp;
10470                         CHECK_OPSIZE (5);
10471                         token = read32 (ip + 1);
10472                         klass = mini_get_class (method, token, generic_context);
10473                         CHECK_TYPELOAD (klass);
10474                         if (sp [0]->type != STACK_OBJ)
10475                                 UNVERIFIED;
10476
10477                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10478                         CHECK_CFG_EXCEPTION;
10479
10480                         *sp ++ = ins;
10481                         ip += 5;
10482                         break;
10483                 case CEE_ISINST: {
10484                         CHECK_STACK (1);
10485                         --sp;
10486                         CHECK_OPSIZE (5);
10487                         token = read32 (ip + 1);
10488                         klass = mini_get_class (method, token, generic_context);
10489                         CHECK_TYPELOAD (klass);
10490                         if (sp [0]->type != STACK_OBJ)
10491                                 UNVERIFIED;
10492  
10493                         context_used = mini_class_check_context_used (cfg, klass);
10494
10495                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10496                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10497                                 MonoInst *args [3];
10498
10499                                 /* obj */
10500                                 args [0] = *sp;
10501
10502                                 /* klass */
10503                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10504
10505                                 /* inline cache*/
10506                                 if (cfg->compile_aot)
10507                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
10508                                 else
10509                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10510
10511                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10512                                 ip += 5;
10513                                 inline_costs += 2;
10514                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10515                                 MonoMethod *mono_isinst;
10516                                 MonoInst *iargs [1];
10517                                 int costs;
10518
10519                                 mono_isinst = mono_marshal_get_isinst (klass); 
10520                                 iargs [0] = sp [0];
10521
10522                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10523                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10524                                 CHECK_CFG_EXCEPTION;
10525                                 g_assert (costs > 0);
10526                                 
10527                                 ip += 5;
10528                                 cfg->real_offset += 5;
10529
10530                                 *sp++= iargs [0];
10531
10532                                 inline_costs += costs;
10533                         }
10534                         else {
10535                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10536                                 CHECK_CFG_EXCEPTION;
10537                                 bblock = cfg->cbb;
10538                                 *sp ++ = ins;
10539                                 ip += 5;
10540                         }
10541                         break;
10542                 }
10543                 case CEE_UNBOX_ANY: {
10544                         MonoInst *res, *addr;
10545
10546                         CHECK_STACK (1);
10547                         --sp;
10548                         CHECK_OPSIZE (5);
10549                         token = read32 (ip + 1);
10550                         klass = mini_get_class (method, token, generic_context);
10551                         CHECK_TYPELOAD (klass);
10552  
10553                         mono_save_token_info (cfg, image, token, klass);
10554
10555                         context_used = mini_class_check_context_used (cfg, klass);
10556
10557                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10558                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10559                                 inline_costs += 2;
10560                         } else if (generic_class_is_reference_type (cfg, klass)) {
10561                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10562                                 CHECK_CFG_EXCEPTION;
10563                         } else if (mono_class_is_nullable (klass)) {
10564                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10565                         } else {
10566                                 addr = handle_unbox (cfg, klass, sp, context_used);
10567                                 /* LDOBJ */
10568                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10569                                 res = ins;
10570                                 inline_costs += 2;
10571                         }
10572
10573                         *sp ++ = res;
10574                         ip += 5;
10575                         break;
10576                 }
10577                 case CEE_BOX: {
10578                         MonoInst *val;
10579                         MonoClass *enum_class;
10580                         MonoMethod *has_flag;
10581
10582                         CHECK_STACK (1);
10583                         --sp;
10584                         val = *sp;
10585                         CHECK_OPSIZE (5);
10586                         token = read32 (ip + 1);
10587                         klass = mini_get_class (method, token, generic_context);
10588                         CHECK_TYPELOAD (klass);
10589
10590                         mono_save_token_info (cfg, image, token, klass);
10591
10592                         context_used = mini_class_check_context_used (cfg, klass);
10593
10594                         if (generic_class_is_reference_type (cfg, klass)) {
10595                                 *sp++ = val;
10596                                 ip += 5;
10597                                 break;
10598                         }
10599
10600                         if (klass == mono_defaults.void_class)
10601                                 UNVERIFIED;
10602                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10603                                 UNVERIFIED;
10604                         /* frequent check in generic code: box (struct), brtrue */
10605
10606                         /*
10607                          * Look for:
10608                          *
10609                          *   <push int/long ptr>
10610                          *   <push int/long>
10611                          *   box MyFlags
10612                          *   constrained. MyFlags
10613                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10614                          *
10615                          * If we find this sequence and the operand types on box and constrained
10616                          * are equal, we can emit a specialized instruction sequence instead of
10617                          * the very slow HasFlag () call.
10618                          */
10619                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10620                             /* Cheap checks first. */
10621                             ip + 5 + 6 + 5 < end &&
10622                             ip [5] == CEE_PREFIX1 &&
10623                             ip [6] == CEE_CONSTRAINED_ &&
10624                             ip [11] == CEE_CALLVIRT &&
10625                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10626                             mono_class_is_enum (klass) &&
10627                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10628                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10629                             has_flag->klass == mono_defaults.enum_class &&
10630                             !strcmp (has_flag->name, "HasFlag") &&
10631                             has_flag->signature->hasthis &&
10632                             has_flag->signature->param_count == 1) {
10633                                 CHECK_TYPELOAD (enum_class);
10634
10635                                 if (enum_class == klass) {
10636                                         MonoInst *enum_this, *enum_flag;
10637
10638                                         ip += 5 + 6 + 5;
10639                                         --sp;
10640
10641                                         enum_this = sp [0];
10642                                         enum_flag = sp [1];
10643
10644                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10645                                         break;
10646                                 }
10647                         }
10648
10649                         // FIXME: LLVM can't handle the inconsistent bb linking
10650                         if (!mono_class_is_nullable (klass) &&
10651                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10652                                 (ip [5] == CEE_BRTRUE || 
10653                                  ip [5] == CEE_BRTRUE_S ||
10654                                  ip [5] == CEE_BRFALSE ||
10655                                  ip [5] == CEE_BRFALSE_S)) {
10656                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10657                                 int dreg;
10658                                 MonoBasicBlock *true_bb, *false_bb;
10659
10660                                 ip += 5;
10661
10662                                 if (cfg->verbose_level > 3) {
10663                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10664                                         printf ("<box+brtrue opt>\n");
10665                                 }
10666
10667                                 switch (*ip) {
10668                                 case CEE_BRTRUE_S:
10669                                 case CEE_BRFALSE_S:
10670                                         CHECK_OPSIZE (2);
10671                                         ip++;
10672                                         target = ip + 1 + (signed char)(*ip);
10673                                         ip++;
10674                                         break;
10675                                 case CEE_BRTRUE:
10676                                 case CEE_BRFALSE:
10677                                         CHECK_OPSIZE (5);
10678                                         ip++;
10679                                         target = ip + 4 + (gint)(read32 (ip));
10680                                         ip += 4;
10681                                         break;
10682                                 default:
10683                                         g_assert_not_reached ();
10684                                 }
10685
10686                                 /* 
10687                                  * We need to link both bblocks, since it is needed for handling stack
10688                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10689                                  * Branching to only one of them would lead to inconsistencies, so
10690                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10691                                  */
10692                                 GET_BBLOCK (cfg, true_bb, target);
10693                                 GET_BBLOCK (cfg, false_bb, ip);
10694
10695                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10696                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10697
10698                                 if (sp != stack_start) {
10699                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10700                                         sp = stack_start;
10701                                         CHECK_UNVERIFIABLE (cfg);
10702                                 }
10703
10704                                 if (COMPILE_LLVM (cfg)) {
10705                                         dreg = alloc_ireg (cfg);
10706                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10707                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10708
10709                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10710                                 } else {
10711                                         /* The JIT can't eliminate the iconst+compare */
10712                                         MONO_INST_NEW (cfg, ins, OP_BR);
10713                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10714                                         MONO_ADD_INS (cfg->cbb, ins);
10715                                 }
10716
10717                                 start_new_bblock = 1;
10718                                 break;
10719                         }
10720
10721                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10722
10723                         CHECK_CFG_EXCEPTION;
10724                         ip += 5;
10725                         inline_costs += 1;
10726                         break;
10727                 }
10728                 case CEE_UNBOX: {
10729                         CHECK_STACK (1);
10730                         --sp;
10731                         CHECK_OPSIZE (5);
10732                         token = read32 (ip + 1);
10733                         klass = mini_get_class (method, token, generic_context);
10734                         CHECK_TYPELOAD (klass);
10735
10736                         mono_save_token_info (cfg, image, token, klass);
10737
10738                         context_used = mini_class_check_context_used (cfg, klass);
10739
10740                         if (mono_class_is_nullable (klass)) {
10741                                 MonoInst *val;
10742
10743                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10744                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10745
10746                                 *sp++= ins;
10747                         } else {
10748                                 ins = handle_unbox (cfg, klass, sp, context_used);
10749                                 *sp++ = ins;
10750                         }
10751                         ip += 5;
10752                         inline_costs += 2;
10753                         break;
10754                 }
10755                 case CEE_LDFLD:
10756                 case CEE_LDFLDA:
10757                 case CEE_STFLD:
10758                 case CEE_LDSFLD:
10759                 case CEE_LDSFLDA:
10760                 case CEE_STSFLD: {
10761                         MonoClassField *field;
10762 #ifndef DISABLE_REMOTING
10763                         int costs;
10764 #endif
10765                         guint foffset;
10766                         gboolean is_instance;
10767                         int op;
10768                         gpointer addr = NULL;
10769                         gboolean is_special_static;
10770                         MonoType *ftype;
10771                         MonoInst *store_val = NULL;
10772                         MonoInst *thread_ins;
10773
10774                         op = *ip;
10775                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10776                         if (is_instance) {
10777                                 if (op == CEE_STFLD) {
10778                                         CHECK_STACK (2);
10779                                         sp -= 2;
10780                                         store_val = sp [1];
10781                                 } else {
10782                                         CHECK_STACK (1);
10783                                         --sp;
10784                                 }
10785                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10786                                         UNVERIFIED;
10787                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10788                                         UNVERIFIED;
10789                         } else {
10790                                 if (op == CEE_STSFLD) {
10791                                         CHECK_STACK (1);
10792                                         sp--;
10793                                         store_val = sp [0];
10794                                 }
10795                         }
10796
10797                         CHECK_OPSIZE (5);
10798                         token = read32 (ip + 1);
10799                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10800                                 field = mono_method_get_wrapper_data (method, token);
10801                                 klass = field->parent;
10802                         }
10803                         else {
10804                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10805                                 CHECK_CFG_ERROR;
10806                         }
10807                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10808                                 FIELD_ACCESS_FAILURE (method, field);
10809                         mono_class_init (klass);
10810
10811                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10812                                 UNVERIFIED;
10813
10814                         /* if the class is Critical then transparent code cannot access it's fields */
10815                         if (!is_instance && mono_security_core_clr_enabled ())
10816                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10817
10818                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10819                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10820                         if (mono_security_core_clr_enabled ())
10821                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10822                         */
10823
10824                         /*
10825                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10826                          * the static case.
10827                          */
10828                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10829                                 switch (op) {
10830                                 case CEE_LDFLD:
10831                                         op = CEE_LDSFLD;
10832                                         break;
10833                                 case CEE_STFLD:
10834                                         op = CEE_STSFLD;
10835                                         break;
10836                                 case CEE_LDFLDA:
10837                                         op = CEE_LDSFLDA;
10838                                         break;
10839                                 default:
10840                                         g_assert_not_reached ();
10841                                 }
10842                                 is_instance = FALSE;
10843                         }
10844
10845                         context_used = mini_class_check_context_used (cfg, klass);
10846
10847                         /* INSTANCE CASE */
10848
10849                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10850                         if (op == CEE_STFLD) {
10851                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10852                                         UNVERIFIED;
10853 #ifndef DISABLE_REMOTING
10854                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10855                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10856                                         MonoInst *iargs [5];
10857
10858                                         GSHAREDVT_FAILURE (op);
10859
10860                                         iargs [0] = sp [0];
10861                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10862                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10863                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10864                                                     field->offset);
10865                                         iargs [4] = sp [1];
10866
10867                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10868                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10869                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10870                                                 CHECK_CFG_EXCEPTION;
10871                                                 g_assert (costs > 0);
10872                                                       
10873                                                 cfg->real_offset += 5;
10874
10875                                                 inline_costs += costs;
10876                                         } else {
10877                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10878                                         }
10879                                 } else
10880 #endif
10881                                 {
10882                                         MonoInst *store;
10883
10884                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10885
10886                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10887                                                 MonoInst *offset_ins;
10888
10889                                                 context_used = mini_class_check_context_used (cfg, klass);
10890
10891                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10892                                                 dreg = alloc_ireg_mp (cfg);
10893                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10894                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10895                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10896                                         } else {
10897                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10898                                         }
10899                                         if (sp [0]->opcode != OP_LDADDR)
10900                                                 store->flags |= MONO_INST_FAULT;
10901
10902                                 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)) {
10903                                         /* insert call to write barrier */
10904                                         MonoInst *ptr;
10905                                         int dreg;
10906
10907                                         dreg = alloc_ireg_mp (cfg);
10908                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10909                                         emit_write_barrier (cfg, ptr, sp [1]);
10910                                 }
10911
10912                                         store->flags |= ins_flag;
10913                                 }
10914                                 ins_flag = 0;
10915                                 ip += 5;
10916                                 break;
10917                         }
10918
10919 #ifndef DISABLE_REMOTING
10920                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10921                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10922                                 MonoInst *iargs [4];
10923
10924                                 GSHAREDVT_FAILURE (op);
10925
10926                                 iargs [0] = sp [0];
10927                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10928                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10929                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10930                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10931                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10932                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10933                                         CHECK_CFG_EXCEPTION;
10934                                         g_assert (costs > 0);
10935                                                       
10936                                         cfg->real_offset += 5;
10937
10938                                         *sp++ = iargs [0];
10939
10940                                         inline_costs += costs;
10941                                 } else {
10942                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10943                                         *sp++ = ins;
10944                                 }
10945                         } else 
10946 #endif
10947                         if (is_instance) {
10948                                 if (sp [0]->type == STACK_VTYPE) {
10949                                         MonoInst *var;
10950
10951                                         /* Have to compute the address of the variable */
10952
10953                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10954                                         if (!var)
10955                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10956                                         else
10957                                                 g_assert (var->klass == klass);
10958                                         
10959                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10960                                         sp [0] = ins;
10961                                 }
10962
10963                                 if (op == CEE_LDFLDA) {
10964                                         if (is_magic_tls_access (field)) {
10965                                                 GSHAREDVT_FAILURE (*ip);
10966                                                 ins = sp [0];
10967                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10968                                         } else {
10969                                                 if (sp [0]->type == STACK_OBJ) {
10970                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10971                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10972                                                 }
10973
10974                                                 dreg = alloc_ireg_mp (cfg);
10975
10976                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10977                                                         MonoInst *offset_ins;
10978
10979                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10980                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10981                                                 } else {
10982                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10983                                                 }
10984                                                 ins->klass = mono_class_from_mono_type (field->type);
10985                                                 ins->type = STACK_MP;
10986                                                 *sp++ = ins;
10987                                         }
10988                                 } else {
10989                                         MonoInst *load;
10990
10991                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10992
10993                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10994                                                 MonoInst *offset_ins;
10995
10996                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10997                                                 dreg = alloc_ireg_mp (cfg);
10998                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10999                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11000                                         } else {
11001                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11002                                         }
11003                                         load->flags |= ins_flag;
11004                                         if (sp [0]->opcode != OP_LDADDR)
11005                                                 load->flags |= MONO_INST_FAULT;
11006                                         *sp++ = load;
11007                                 }
11008                         }
11009
11010                         if (is_instance) {
11011                                 ins_flag = 0;
11012                                 ip += 5;
11013                                 break;
11014                         }
11015
11016                         /* STATIC CASE */
11017
11018                         /*
11019                          * We can only support shared generic static
11020                          * field access on architectures where the
11021                          * trampoline code has been extended to handle
11022                          * the generic class init.
11023                          */
11024 #ifndef MONO_ARCH_VTABLE_REG
11025                         GENERIC_SHARING_FAILURE (op);
11026 #endif
11027
11028                         context_used = mini_class_check_context_used (cfg, klass);
11029
11030                         ftype = mono_field_get_type (field);
11031
11032                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11033                                 UNVERIFIED;
11034
11035                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11036                          * to be called here.
11037                          */
11038                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11039                                 mono_class_vtable (cfg->domain, klass);
11040                                 CHECK_TYPELOAD (klass);
11041                         }
11042                         mono_domain_lock (cfg->domain);
11043                         if (cfg->domain->special_static_fields)
11044                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11045                         mono_domain_unlock (cfg->domain);
11046
11047                         is_special_static = mono_class_field_is_special_static (field);
11048
11049                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11050                                 thread_ins = mono_get_thread_intrinsic (cfg);
11051                         else
11052                                 thread_ins = NULL;
11053
11054                         /* Generate IR to compute the field address */
11055                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11056                                 /*
11057                                  * Fast access to TLS data
11058                                  * Inline version of get_thread_static_data () in
11059                                  * threads.c.
11060                                  */
11061                                 guint32 offset;
11062                                 int idx, static_data_reg, array_reg, dreg;
11063
11064                                 GSHAREDVT_FAILURE (op);
11065
11066                                 // offset &= 0x7fffffff;
11067                                 // idx = (offset >> 24) - 1;
11068                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
11069                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11070                                 static_data_reg = alloc_ireg (cfg);
11071                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11072
11073                                 if (cfg->compile_aot) {
11074                                         int offset_reg, offset2_reg, idx_reg;
11075
11076                                         /* For TLS variables, this will return the TLS offset */
11077                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11078                                         offset_reg = ins->dreg;
11079                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11080                                         idx_reg = alloc_ireg (cfg);
11081                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
11082                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
11083                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11084                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11085                                         array_reg = alloc_ireg (cfg);
11086                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11087                                         offset2_reg = alloc_ireg (cfg);
11088                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
11089                                         dreg = alloc_ireg (cfg);
11090                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11091                                 } else {
11092                                         offset = (gsize)addr & 0x7fffffff;
11093                                         idx = (offset >> 24) - 1;
11094
11095                                         array_reg = alloc_ireg (cfg);
11096                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11097                                         dreg = alloc_ireg (cfg);
11098                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
11099                                 }
11100                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11101                                         (cfg->compile_aot && is_special_static) ||
11102                                         (context_used && is_special_static)) {
11103                                 MonoInst *iargs [2];
11104
11105                                 g_assert (field->parent);
11106                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11107                                 if (context_used) {
11108                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11109                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11110                                 } else {
11111                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11112                                 }
11113                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11114                         } else if (context_used) {
11115                                 MonoInst *static_data;
11116
11117                                 /*
11118                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11119                                         method->klass->name_space, method->klass->name, method->name,
11120                                         depth, field->offset);
11121                                 */
11122
11123                                 if (mono_class_needs_cctor_run (klass, method))
11124                                         emit_generic_class_init (cfg, klass);
11125
11126                                 /*
11127                                  * The pointer we're computing here is
11128                                  *
11129                                  *   super_info.static_data + field->offset
11130                                  */
11131                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11132                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11133
11134                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11135                                         MonoInst *offset_ins;
11136
11137                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11138                                         dreg = alloc_ireg_mp (cfg);
11139                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11140                                 } else if (field->offset == 0) {
11141                                         ins = static_data;
11142                                 } else {
11143                                         int addr_reg = mono_alloc_preg (cfg);
11144                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11145                                 }
11146                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11147                                 MonoInst *iargs [2];
11148
11149                                 g_assert (field->parent);
11150                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11151                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11152                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11153                         } else {
11154                                 MonoVTable *vtable = NULL;
11155
11156                                 if (!cfg->compile_aot)
11157                                         vtable = mono_class_vtable (cfg->domain, klass);
11158                                 CHECK_TYPELOAD (klass);
11159
11160                                 if (!addr) {
11161                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11162                                                 if (!(g_slist_find (class_inits, klass))) {
11163                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
11164                                                         if (cfg->verbose_level > 2)
11165                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11166                                                         class_inits = g_slist_prepend (class_inits, klass);
11167                                                 }
11168                                         } else {
11169                                                 if (cfg->run_cctors) {
11170                                                         MonoException *ex;
11171                                                         /* This makes so that inline cannot trigger */
11172                                                         /* .cctors: too many apps depend on them */
11173                                                         /* running with a specific order... */
11174                                                         g_assert (vtable);
11175                                                         if (! vtable->initialized)
11176                                                                 INLINE_FAILURE ("class init");
11177                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11178                                                         if (ex) {
11179                                                                 set_exception_object (cfg, ex);
11180                                                                 goto exception_exit;
11181                                                         }
11182                                                 }
11183                                         }
11184                                         if (cfg->compile_aot)
11185                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11186                                         else {
11187                                                 g_assert (vtable);
11188                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11189                                                 g_assert (addr);
11190                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11191                                         }
11192                                 } else {
11193                                         MonoInst *iargs [1];
11194                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11195                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11196                                 }
11197                         }
11198
11199                         /* Generate IR to do the actual load/store operation */
11200
11201                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11202                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11203                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11204                         }
11205
11206                         if (op == CEE_LDSFLDA) {
11207                                 ins->klass = mono_class_from_mono_type (ftype);
11208                                 ins->type = STACK_PTR;
11209                                 *sp++ = ins;
11210                         } else if (op == CEE_STSFLD) {
11211                                 MonoInst *store;
11212
11213                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11214                                 store->flags |= ins_flag;
11215                         } else {
11216                                 gboolean is_const = FALSE;
11217                                 MonoVTable *vtable = NULL;
11218                                 gpointer addr = NULL;
11219
11220                                 if (!context_used) {
11221                                         vtable = mono_class_vtable (cfg->domain, klass);
11222                                         CHECK_TYPELOAD (klass);
11223                                 }
11224                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11225                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11226                                         int ro_type = ftype->type;
11227                                         if (!addr)
11228                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11229                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11230                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11231                                         }
11232
11233                                         GSHAREDVT_FAILURE (op);
11234
11235                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11236                                         is_const = TRUE;
11237                                         switch (ro_type) {
11238                                         case MONO_TYPE_BOOLEAN:
11239                                         case MONO_TYPE_U1:
11240                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11241                                                 sp++;
11242                                                 break;
11243                                         case MONO_TYPE_I1:
11244                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11245                                                 sp++;
11246                                                 break;                                          
11247                                         case MONO_TYPE_CHAR:
11248                                         case MONO_TYPE_U2:
11249                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11250                                                 sp++;
11251                                                 break;
11252                                         case MONO_TYPE_I2:
11253                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11254                                                 sp++;
11255                                                 break;
11256                                                 break;
11257                                         case MONO_TYPE_I4:
11258                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11259                                                 sp++;
11260                                                 break;                                          
11261                                         case MONO_TYPE_U4:
11262                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11263                                                 sp++;
11264                                                 break;
11265                                         case MONO_TYPE_I:
11266                                         case MONO_TYPE_U:
11267                                         case MONO_TYPE_PTR:
11268                                         case MONO_TYPE_FNPTR:
11269                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11270                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11271                                                 sp++;
11272                                                 break;
11273                                         case MONO_TYPE_STRING:
11274                                         case MONO_TYPE_OBJECT:
11275                                         case MONO_TYPE_CLASS:
11276                                         case MONO_TYPE_SZARRAY:
11277                                         case MONO_TYPE_ARRAY:
11278                                                 if (!mono_gc_is_moving ()) {
11279                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11280                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11281                                                         sp++;
11282                                                 } else {
11283                                                         is_const = FALSE;
11284                                                 }
11285                                                 break;
11286                                         case MONO_TYPE_I8:
11287                                         case MONO_TYPE_U8:
11288                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11289                                                 sp++;
11290                                                 break;
11291                                         case MONO_TYPE_R4:
11292                                         case MONO_TYPE_R8:
11293                                         case MONO_TYPE_VALUETYPE:
11294                                         default:
11295                                                 is_const = FALSE;
11296                                                 break;
11297                                         }
11298                                 }
11299
11300                                 if (!is_const) {
11301                                         MonoInst *load;
11302
11303                                         CHECK_STACK_OVF (1);
11304
11305                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11306                                         load->flags |= ins_flag;
11307                                         ins_flag = 0;
11308                                         *sp++ = load;
11309                                 }
11310                         }
11311
11312                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11313                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11314                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11315                         }
11316
11317                         ins_flag = 0;
11318                         ip += 5;
11319                         break;
11320                 }
11321                 case CEE_STOBJ:
11322                         CHECK_STACK (2);
11323                         sp -= 2;
11324                         CHECK_OPSIZE (5);
11325                         token = read32 (ip + 1);
11326                         klass = mini_get_class (method, token, generic_context);
11327                         CHECK_TYPELOAD (klass);
11328                         if (ins_flag & MONO_INST_VOLATILE) {
11329                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11330                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11331                         }
11332                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11333                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11334                         ins->flags |= ins_flag;
11335                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11336                                         generic_class_is_reference_type (cfg, klass)) {
11337                                 /* insert call to write barrier */
11338                                 emit_write_barrier (cfg, sp [0], sp [1]);
11339                         }
11340                         ins_flag = 0;
11341                         ip += 5;
11342                         inline_costs += 1;
11343                         break;
11344
11345                         /*
11346                          * Array opcodes
11347                          */
11348                 case CEE_NEWARR: {
11349                         MonoInst *len_ins;
11350                         const char *data_ptr;
11351                         int data_size = 0;
11352                         guint32 field_token;
11353
11354                         CHECK_STACK (1);
11355                         --sp;
11356
11357                         CHECK_OPSIZE (5);
11358                         token = read32 (ip + 1);
11359
11360                         klass = mini_get_class (method, token, generic_context);
11361                         CHECK_TYPELOAD (klass);
11362
11363                         context_used = mini_class_check_context_used (cfg, klass);
11364
11365                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11366                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11367                                 ins->sreg1 = sp [0]->dreg;
11368                                 ins->type = STACK_I4;
11369                                 ins->dreg = alloc_ireg (cfg);
11370                                 MONO_ADD_INS (cfg->cbb, ins);
11371                                 *sp = mono_decompose_opcode (cfg, ins, &bblock);
11372                         }
11373
11374                         if (context_used) {
11375                                 MonoInst *args [3];
11376                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11377                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11378
11379                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11380
11381                                 /* vtable */
11382                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11383                                         array_class, MONO_RGCTX_INFO_VTABLE);
11384                                 /* array len */
11385                                 args [1] = sp [0];
11386
11387                                 if (managed_alloc)
11388                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11389                                 else
11390                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11391                         } else {
11392                                 if (cfg->opt & MONO_OPT_SHARED) {
11393                                         /* Decompose now to avoid problems with references to the domainvar */
11394                                         MonoInst *iargs [3];
11395
11396                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11397                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11398                                         iargs [2] = sp [0];
11399
11400                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11401                                 } else {
11402                                         /* Decompose later since it is needed by abcrem */
11403                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11404                                         mono_class_vtable (cfg->domain, array_type);
11405                                         CHECK_TYPELOAD (array_type);
11406
11407                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11408                                         ins->dreg = alloc_ireg_ref (cfg);
11409                                         ins->sreg1 = sp [0]->dreg;
11410                                         ins->inst_newa_class = klass;
11411                                         ins->type = STACK_OBJ;
11412                                         ins->klass = array_type;
11413                                         MONO_ADD_INS (cfg->cbb, ins);
11414                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11415                                         cfg->cbb->has_array_access = TRUE;
11416
11417                                         /* Needed so mono_emit_load_get_addr () gets called */
11418                                         mono_get_got_var (cfg);
11419                                 }
11420                         }
11421
11422                         len_ins = sp [0];
11423                         ip += 5;
11424                         *sp++ = ins;
11425                         inline_costs += 1;
11426
11427                         /* 
11428                          * we inline/optimize the initialization sequence if possible.
11429                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11430                          * for small sizes open code the memcpy
11431                          * ensure the rva field is big enough
11432                          */
11433                         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))) {
11434                                 MonoMethod *memcpy_method = get_memcpy_method ();
11435                                 MonoInst *iargs [3];
11436                                 int add_reg = alloc_ireg_mp (cfg);
11437
11438                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11439                                 if (cfg->compile_aot) {
11440                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11441                                 } else {
11442                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11443                                 }
11444                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11445                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11446                                 ip += 11;
11447                         }
11448
11449                         break;
11450                 }
11451                 case CEE_LDLEN:
11452                         CHECK_STACK (1);
11453                         --sp;
11454                         if (sp [0]->type != STACK_OBJ)
11455                                 UNVERIFIED;
11456
11457                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11458                         ins->dreg = alloc_preg (cfg);
11459                         ins->sreg1 = sp [0]->dreg;
11460                         ins->type = STACK_I4;
11461                         /* This flag will be inherited by the decomposition */
11462                         ins->flags |= MONO_INST_FAULT;
11463                         MONO_ADD_INS (cfg->cbb, ins);
11464                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11465                         cfg->cbb->has_array_access = TRUE;
11466                         ip ++;
11467                         *sp++ = ins;
11468                         break;
11469                 case CEE_LDELEMA:
11470                         CHECK_STACK (2);
11471                         sp -= 2;
11472                         CHECK_OPSIZE (5);
11473                         if (sp [0]->type != STACK_OBJ)
11474                                 UNVERIFIED;
11475
11476                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11477
11478                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11479                         CHECK_TYPELOAD (klass);
11480                         /* we need to make sure that this array is exactly the type it needs
11481                          * to be for correctness. the wrappers are lax with their usage
11482                          * so we need to ignore them here
11483                          */
11484                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11485                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11486                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11487                                 CHECK_TYPELOAD (array_class);
11488                         }
11489
11490                         readonly = FALSE;
11491                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11492                         *sp++ = ins;
11493                         ip += 5;
11494                         break;
11495                 case CEE_LDELEM:
11496                 case CEE_LDELEM_I1:
11497                 case CEE_LDELEM_U1:
11498                 case CEE_LDELEM_I2:
11499                 case CEE_LDELEM_U2:
11500                 case CEE_LDELEM_I4:
11501                 case CEE_LDELEM_U4:
11502                 case CEE_LDELEM_I8:
11503                 case CEE_LDELEM_I:
11504                 case CEE_LDELEM_R4:
11505                 case CEE_LDELEM_R8:
11506                 case CEE_LDELEM_REF: {
11507                         MonoInst *addr;
11508
11509                         CHECK_STACK (2);
11510                         sp -= 2;
11511
11512                         if (*ip == CEE_LDELEM) {
11513                                 CHECK_OPSIZE (5);
11514                                 token = read32 (ip + 1);
11515                                 klass = mini_get_class (method, token, generic_context);
11516                                 CHECK_TYPELOAD (klass);
11517                                 mono_class_init (klass);
11518                         }
11519                         else
11520                                 klass = array_access_to_klass (*ip);
11521
11522                         if (sp [0]->type != STACK_OBJ)
11523                                 UNVERIFIED;
11524
11525                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11526
11527                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11528                                 // FIXME-VT: OP_ICONST optimization
11529                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11530                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11531                                 ins->opcode = OP_LOADV_MEMBASE;
11532                         } else if (sp [1]->opcode == OP_ICONST) {
11533                                 int array_reg = sp [0]->dreg;
11534                                 int index_reg = sp [1]->dreg;
11535                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11536
11537                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11538                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11539                         } else {
11540                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11541                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11542                         }
11543                         *sp++ = ins;
11544                         if (*ip == CEE_LDELEM)
11545                                 ip += 5;
11546                         else
11547                                 ++ip;
11548                         break;
11549                 }
11550                 case CEE_STELEM_I:
11551                 case CEE_STELEM_I1:
11552                 case CEE_STELEM_I2:
11553                 case CEE_STELEM_I4:
11554                 case CEE_STELEM_I8:
11555                 case CEE_STELEM_R4:
11556                 case CEE_STELEM_R8:
11557                 case CEE_STELEM_REF:
11558                 case CEE_STELEM: {
11559                         CHECK_STACK (3);
11560                         sp -= 3;
11561
11562                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11563
11564                         if (*ip == CEE_STELEM) {
11565                                 CHECK_OPSIZE (5);
11566                                 token = read32 (ip + 1);
11567                                 klass = mini_get_class (method, token, generic_context);
11568                                 CHECK_TYPELOAD (klass);
11569                                 mono_class_init (klass);
11570                         }
11571                         else
11572                                 klass = array_access_to_klass (*ip);
11573
11574                         if (sp [0]->type != STACK_OBJ)
11575                                 UNVERIFIED;
11576
11577                         emit_array_store (cfg, klass, sp, TRUE);
11578
11579                         if (*ip == CEE_STELEM)
11580                                 ip += 5;
11581                         else
11582                                 ++ip;
11583                         inline_costs += 1;
11584                         break;
11585                 }
11586                 case CEE_CKFINITE: {
11587                         CHECK_STACK (1);
11588                         --sp;
11589
11590                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11591                         ins->sreg1 = sp [0]->dreg;
11592                         ins->dreg = alloc_freg (cfg);
11593                         ins->type = STACK_R8;
11594                         MONO_ADD_INS (bblock, ins);
11595
11596                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
11597
11598                         ++ip;
11599                         break;
11600                 }
11601                 case CEE_REFANYVAL: {
11602                         MonoInst *src_var, *src;
11603
11604                         int klass_reg = alloc_preg (cfg);
11605                         int dreg = alloc_preg (cfg);
11606
11607                         GSHAREDVT_FAILURE (*ip);
11608
11609                         CHECK_STACK (1);
11610                         MONO_INST_NEW (cfg, ins, *ip);
11611                         --sp;
11612                         CHECK_OPSIZE (5);
11613                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11614                         CHECK_TYPELOAD (klass);
11615
11616                         context_used = mini_class_check_context_used (cfg, klass);
11617
11618                         // FIXME:
11619                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11620                         if (!src_var)
11621                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11622                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11623                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11624
11625                         if (context_used) {
11626                                 MonoInst *klass_ins;
11627
11628                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11629                                                 klass, MONO_RGCTX_INFO_KLASS);
11630
11631                                 // FIXME:
11632                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11633                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11634                         } else {
11635                                 mini_emit_class_check (cfg, klass_reg, klass);
11636                         }
11637                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11638                         ins->type = STACK_MP;
11639                         *sp++ = ins;
11640                         ip += 5;
11641                         break;
11642                 }
11643                 case CEE_MKREFANY: {
11644                         MonoInst *loc, *addr;
11645
11646                         GSHAREDVT_FAILURE (*ip);
11647
11648                         CHECK_STACK (1);
11649                         MONO_INST_NEW (cfg, ins, *ip);
11650                         --sp;
11651                         CHECK_OPSIZE (5);
11652                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11653                         CHECK_TYPELOAD (klass);
11654
11655                         context_used = mini_class_check_context_used (cfg, klass);
11656
11657                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11658                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11659
11660                         if (context_used) {
11661                                 MonoInst *const_ins;
11662                                 int type_reg = alloc_preg (cfg);
11663
11664                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11665                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11666                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11667                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11668                         } else if (cfg->compile_aot) {
11669                                 int const_reg = alloc_preg (cfg);
11670                                 int type_reg = alloc_preg (cfg);
11671
11672                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11673                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11674                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11675                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11676                         } else {
11677                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11678                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11679                         }
11680                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11681
11682                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11683                         ins->type = STACK_VTYPE;
11684                         ins->klass = mono_defaults.typed_reference_class;
11685                         *sp++ = ins;
11686                         ip += 5;
11687                         break;
11688                 }
11689                 case CEE_LDTOKEN: {
11690                         gpointer handle;
11691                         MonoClass *handle_class;
11692
11693                         CHECK_STACK_OVF (1);
11694
11695                         CHECK_OPSIZE (5);
11696                         n = read32 (ip + 1);
11697
11698                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11699                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11700                                 handle = mono_method_get_wrapper_data (method, n);
11701                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11702                                 if (handle_class == mono_defaults.typehandle_class)
11703                                         handle = &((MonoClass*)handle)->byval_arg;
11704                         }
11705                         else {
11706                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11707                                 CHECK_CFG_ERROR;
11708                         }
11709                         if (!handle)
11710                                 LOAD_ERROR;
11711                         mono_class_init (handle_class);
11712                         if (cfg->generic_sharing_context) {
11713                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11714                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11715                                         /* This case handles ldtoken
11716                                            of an open type, like for
11717                                            typeof(Gen<>). */
11718                                         context_used = 0;
11719                                 } else if (handle_class == mono_defaults.typehandle_class) {
11720                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11721                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11722                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11723                                 else if (handle_class == mono_defaults.methodhandle_class)
11724                                         context_used = mini_method_check_context_used (cfg, handle);
11725                                 else
11726                                         g_assert_not_reached ();
11727                         }
11728
11729                         if ((cfg->opt & MONO_OPT_SHARED) &&
11730                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11731                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11732                                 MonoInst *addr, *vtvar, *iargs [3];
11733                                 int method_context_used;
11734
11735                                 method_context_used = mini_method_check_context_used (cfg, method);
11736
11737                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11738
11739                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11740                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11741                                 if (method_context_used) {
11742                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11743                                                 method, MONO_RGCTX_INFO_METHOD);
11744                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11745                                 } else {
11746                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11747                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11748                                 }
11749                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11750
11751                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11752
11753                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11754                         } else {
11755                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11756                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11757                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11758                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11759                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11760                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11761
11762                                         mono_class_init (tclass);
11763                                         if (context_used) {
11764                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11765                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11766                                         } else if (cfg->compile_aot) {
11767                                                 if (method->wrapper_type) {
11768                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11769                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11770                                                                 /* Special case for static synchronized wrappers */
11771                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11772                                                         } else {
11773                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11774                                                                 /* FIXME: n is not a normal token */
11775                                                                 DISABLE_AOT (cfg);
11776                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11777                                                         }
11778                                                 } else {
11779                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11780                                                 }
11781                                         } else {
11782                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11783                                         }
11784                                         ins->type = STACK_OBJ;
11785                                         ins->klass = cmethod->klass;
11786                                         ip += 5;
11787                                 } else {
11788                                         MonoInst *addr, *vtvar;
11789
11790                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11791
11792                                         if (context_used) {
11793                                                 if (handle_class == mono_defaults.typehandle_class) {
11794                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11795                                                                         mono_class_from_mono_type (handle),
11796                                                                         MONO_RGCTX_INFO_TYPE);
11797                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11798                                                         ins = emit_get_rgctx_method (cfg, context_used,
11799                                                                         handle, MONO_RGCTX_INFO_METHOD);
11800                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11801                                                         ins = emit_get_rgctx_field (cfg, context_used,
11802                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11803                                                 } else {
11804                                                         g_assert_not_reached ();
11805                                                 }
11806                                         } else if (cfg->compile_aot) {
11807                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11808                                         } else {
11809                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11810                                         }
11811                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11812                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11813                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11814                                 }
11815                         }
11816
11817                         *sp++ = ins;
11818                         ip += 5;
11819                         break;
11820                 }
11821                 case CEE_THROW:
11822                         CHECK_STACK (1);
11823                         MONO_INST_NEW (cfg, ins, OP_THROW);
11824                         --sp;
11825                         ins->sreg1 = sp [0]->dreg;
11826                         ip++;
11827                         bblock->out_of_line = TRUE;
11828                         MONO_ADD_INS (bblock, ins);
11829                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11830                         MONO_ADD_INS (bblock, ins);
11831                         sp = stack_start;
11832                         
11833                         link_bblock (cfg, bblock, end_bblock);
11834                         start_new_bblock = 1;
11835                         break;
11836                 case CEE_ENDFINALLY:
11837                         /* mono_save_seq_point_info () depends on this */
11838                         if (sp != stack_start)
11839                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11840                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11841                         MONO_ADD_INS (bblock, ins);
11842                         ip++;
11843                         start_new_bblock = 1;
11844
11845                         /*
11846                          * Control will leave the method so empty the stack, otherwise
11847                          * the next basic block will start with a nonempty stack.
11848                          */
11849                         while (sp != stack_start) {
11850                                 sp--;
11851                         }
11852                         break;
11853                 case CEE_LEAVE:
11854                 case CEE_LEAVE_S: {
11855                         GList *handlers;
11856
11857                         if (*ip == CEE_LEAVE) {
11858                                 CHECK_OPSIZE (5);
11859                                 target = ip + 5 + (gint32)read32(ip + 1);
11860                         } else {
11861                                 CHECK_OPSIZE (2);
11862                                 target = ip + 2 + (signed char)(ip [1]);
11863                         }
11864
11865                         /* empty the stack */
11866                         while (sp != stack_start) {
11867                                 sp--;
11868                         }
11869
11870                         /* 
11871                          * If this leave statement is in a catch block, check for a
11872                          * pending exception, and rethrow it if necessary.
11873                          * We avoid doing this in runtime invoke wrappers, since those are called
11874                          * by native code which excepts the wrapper to catch all exceptions.
11875                          */
11876                         for (i = 0; i < header->num_clauses; ++i) {
11877                                 MonoExceptionClause *clause = &header->clauses [i];
11878
11879                                 /* 
11880                                  * Use <= in the final comparison to handle clauses with multiple
11881                                  * leave statements, like in bug #78024.
11882                                  * The ordering of the exception clauses guarantees that we find the
11883                                  * innermost clause.
11884                                  */
11885                                 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) {
11886                                         MonoInst *exc_ins;
11887                                         MonoBasicBlock *dont_throw;
11888
11889                                         /*
11890                                           MonoInst *load;
11891
11892                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11893                                         */
11894
11895                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11896
11897                                         NEW_BBLOCK (cfg, dont_throw);
11898
11899                                         /*
11900                                          * Currently, we always rethrow the abort exception, despite the 
11901                                          * fact that this is not correct. See thread6.cs for an example. 
11902                                          * But propagating the abort exception is more important than 
11903                                          * getting the sematics right.
11904                                          */
11905                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11906                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11907                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11908
11909                                         MONO_START_BB (cfg, dont_throw);
11910                                         bblock = cfg->cbb;
11911                                 }
11912                         }
11913
11914                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11915                                 GList *tmp;
11916                                 MonoExceptionClause *clause;
11917
11918                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11919                                         clause = tmp->data;
11920                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11921                                         g_assert (tblock);
11922                                         link_bblock (cfg, bblock, tblock);
11923                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11924                                         ins->inst_target_bb = tblock;
11925                                         ins->inst_eh_block = clause;
11926                                         MONO_ADD_INS (bblock, ins);
11927                                         bblock->has_call_handler = 1;
11928                                         if (COMPILE_LLVM (cfg)) {
11929                                                 MonoBasicBlock *target_bb;
11930
11931                                                 /* 
11932                                                  * Link the finally bblock with the target, since it will
11933                                                  * conceptually branch there.
11934                                                  * FIXME: Have to link the bblock containing the endfinally.
11935                                                  */
11936                                                 GET_BBLOCK (cfg, target_bb, target);
11937                                                 link_bblock (cfg, tblock, target_bb);
11938                                         }
11939                                 }
11940                                 g_list_free (handlers);
11941                         } 
11942
11943                         MONO_INST_NEW (cfg, ins, OP_BR);
11944                         MONO_ADD_INS (bblock, ins);
11945                         GET_BBLOCK (cfg, tblock, target);
11946                         link_bblock (cfg, bblock, tblock);
11947                         ins->inst_target_bb = tblock;
11948                         start_new_bblock = 1;
11949
11950                         if (*ip == CEE_LEAVE)
11951                                 ip += 5;
11952                         else
11953                                 ip += 2;
11954
11955                         break;
11956                 }
11957
11958                         /*
11959                          * Mono specific opcodes
11960                          */
11961                 case MONO_CUSTOM_PREFIX: {
11962
11963                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11964
11965                         CHECK_OPSIZE (2);
11966                         switch (ip [1]) {
11967                         case CEE_MONO_ICALL: {
11968                                 gpointer func;
11969                                 MonoJitICallInfo *info;
11970
11971                                 token = read32 (ip + 2);
11972                                 func = mono_method_get_wrapper_data (method, token);
11973                                 info = mono_find_jit_icall_by_addr (func);
11974                                 if (!info)
11975                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11976                                 g_assert (info);
11977
11978                                 CHECK_STACK (info->sig->param_count);
11979                                 sp -= info->sig->param_count;
11980
11981                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11982                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11983                                         *sp++ = ins;
11984
11985                                 ip += 6;
11986                                 inline_costs += 10 * num_calls++;
11987
11988                                 break;
11989                         }
11990                         case CEE_MONO_LDPTR: {
11991                                 gpointer ptr;
11992
11993                                 CHECK_STACK_OVF (1);
11994                                 CHECK_OPSIZE (6);
11995                                 token = read32 (ip + 2);
11996
11997                                 ptr = mono_method_get_wrapper_data (method, token);
11998                                 /* FIXME: Generalize this */
11999                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
12000                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12001                                         *sp++ = ins;
12002                                         ip += 6;
12003                                         break;
12004                                 }
12005                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12006                                 *sp++ = ins;
12007                                 ip += 6;
12008                                 inline_costs += 10 * num_calls++;
12009                                 /* Can't embed random pointers into AOT code */
12010                                 DISABLE_AOT (cfg);
12011                                 break;
12012                         }
12013                         case CEE_MONO_JIT_ICALL_ADDR: {
12014                                 MonoJitICallInfo *callinfo;
12015                                 gpointer ptr;
12016
12017                                 CHECK_STACK_OVF (1);
12018                                 CHECK_OPSIZE (6);
12019                                 token = read32 (ip + 2);
12020
12021                                 ptr = mono_method_get_wrapper_data (method, token);
12022                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12023                                 g_assert (callinfo);
12024                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12025                                 *sp++ = ins;
12026                                 ip += 6;
12027                                 inline_costs += 10 * num_calls++;
12028                                 break;
12029                         }
12030                         case CEE_MONO_ICALL_ADDR: {
12031                                 MonoMethod *cmethod;
12032                                 gpointer ptr;
12033
12034                                 CHECK_STACK_OVF (1);
12035                                 CHECK_OPSIZE (6);
12036                                 token = read32 (ip + 2);
12037
12038                                 cmethod = mono_method_get_wrapper_data (method, token);
12039
12040                                 if (cfg->compile_aot) {
12041                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12042                                 } else {
12043                                         ptr = mono_lookup_internal_call (cmethod);
12044                                         g_assert (ptr);
12045                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12046                                 }
12047                                 *sp++ = ins;
12048                                 ip += 6;
12049                                 break;
12050                         }
12051                         case CEE_MONO_VTADDR: {
12052                                 MonoInst *src_var, *src;
12053
12054                                 CHECK_STACK (1);
12055                                 --sp;
12056
12057                                 // FIXME:
12058                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12059                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12060                                 *sp++ = src;
12061                                 ip += 2;
12062                                 break;
12063                         }
12064                         case CEE_MONO_NEWOBJ: {
12065                                 MonoInst *iargs [2];
12066
12067                                 CHECK_STACK_OVF (1);
12068                                 CHECK_OPSIZE (6);
12069                                 token = read32 (ip + 2);
12070                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12071                                 mono_class_init (klass);
12072                                 NEW_DOMAINCONST (cfg, iargs [0]);
12073                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12074                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12075                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12076                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12077                                 ip += 6;
12078                                 inline_costs += 10 * num_calls++;
12079                                 break;
12080                         }
12081                         case CEE_MONO_OBJADDR:
12082                                 CHECK_STACK (1);
12083                                 --sp;
12084                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12085                                 ins->dreg = alloc_ireg_mp (cfg);
12086                                 ins->sreg1 = sp [0]->dreg;
12087                                 ins->type = STACK_MP;
12088                                 MONO_ADD_INS (cfg->cbb, ins);
12089                                 *sp++ = ins;
12090                                 ip += 2;
12091                                 break;
12092                         case CEE_MONO_LDNATIVEOBJ:
12093                                 /*
12094                                  * Similar to LDOBJ, but instead load the unmanaged 
12095                                  * representation of the vtype to the stack.
12096                                  */
12097                                 CHECK_STACK (1);
12098                                 CHECK_OPSIZE (6);
12099                                 --sp;
12100                                 token = read32 (ip + 2);
12101                                 klass = mono_method_get_wrapper_data (method, token);
12102                                 g_assert (klass->valuetype);
12103                                 mono_class_init (klass);
12104
12105                                 {
12106                                         MonoInst *src, *dest, *temp;
12107
12108                                         src = sp [0];
12109                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12110                                         temp->backend.is_pinvoke = 1;
12111                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12112                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12113
12114                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12115                                         dest->type = STACK_VTYPE;
12116                                         dest->klass = klass;
12117
12118                                         *sp ++ = dest;
12119                                         ip += 6;
12120                                 }
12121                                 break;
12122                         case CEE_MONO_RETOBJ: {
12123                                 /*
12124                                  * Same as RET, but return the native representation of a vtype
12125                                  * to the caller.
12126                                  */
12127                                 g_assert (cfg->ret);
12128                                 g_assert (mono_method_signature (method)->pinvoke); 
12129                                 CHECK_STACK (1);
12130                                 --sp;
12131                                 
12132                                 CHECK_OPSIZE (6);
12133                                 token = read32 (ip + 2);    
12134                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12135
12136                                 if (!cfg->vret_addr) {
12137                                         g_assert (cfg->ret_var_is_local);
12138
12139                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12140                                 } else {
12141                                         EMIT_NEW_RETLOADA (cfg, ins);
12142                                 }
12143                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12144                                 
12145                                 if (sp != stack_start)
12146                                         UNVERIFIED;
12147                                 
12148                                 MONO_INST_NEW (cfg, ins, OP_BR);
12149                                 ins->inst_target_bb = end_bblock;
12150                                 MONO_ADD_INS (bblock, ins);
12151                                 link_bblock (cfg, bblock, end_bblock);
12152                                 start_new_bblock = 1;
12153                                 ip += 6;
12154                                 break;
12155                         }
12156                         case CEE_MONO_CISINST:
12157                         case CEE_MONO_CCASTCLASS: {
12158                                 int token;
12159                                 CHECK_STACK (1);
12160                                 --sp;
12161                                 CHECK_OPSIZE (6);
12162                                 token = read32 (ip + 2);
12163                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12164                                 if (ip [1] == CEE_MONO_CISINST)
12165                                         ins = handle_cisinst (cfg, klass, sp [0]);
12166                                 else
12167                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12168                                 bblock = cfg->cbb;
12169                                 *sp++ = ins;
12170                                 ip += 6;
12171                                 break;
12172                         }
12173                         case CEE_MONO_SAVE_LMF:
12174                         case CEE_MONO_RESTORE_LMF:
12175 #ifdef MONO_ARCH_HAVE_LMF_OPS
12176                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12177                                 MONO_ADD_INS (bblock, ins);
12178                                 cfg->need_lmf_area = TRUE;
12179 #endif
12180                                 ip += 2;
12181                                 break;
12182                         case CEE_MONO_CLASSCONST:
12183                                 CHECK_STACK_OVF (1);
12184                                 CHECK_OPSIZE (6);
12185                                 token = read32 (ip + 2);
12186                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12187                                 *sp++ = ins;
12188                                 ip += 6;
12189                                 inline_costs += 10 * num_calls++;
12190                                 break;
12191                         case CEE_MONO_NOT_TAKEN:
12192                                 bblock->out_of_line = TRUE;
12193                                 ip += 2;
12194                                 break;
12195                         case CEE_MONO_TLS: {
12196                                 int key;
12197
12198                                 CHECK_STACK_OVF (1);
12199                                 CHECK_OPSIZE (6);
12200                                 key = (gint32)read32 (ip + 2);
12201                                 g_assert (key < TLS_KEY_NUM);
12202
12203                                 ins = mono_create_tls_get (cfg, key);
12204                                 if (!ins) {
12205                                         if (cfg->compile_aot) {
12206                                                 DISABLE_AOT (cfg);
12207                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12208                                                 ins->dreg = alloc_preg (cfg);
12209                                                 ins->type = STACK_PTR;
12210                                         } else {
12211                                                 g_assert_not_reached ();
12212                                         }
12213                                 }
12214                                 ins->type = STACK_PTR;
12215                                 MONO_ADD_INS (bblock, ins);
12216                                 *sp++ = ins;
12217                                 ip += 6;
12218                                 break;
12219                         }
12220                         case CEE_MONO_DYN_CALL: {
12221                                 MonoCallInst *call;
12222
12223                                 /* It would be easier to call a trampoline, but that would put an
12224                                  * extra frame on the stack, confusing exception handling. So
12225                                  * implement it inline using an opcode for now.
12226                                  */
12227
12228                                 if (!cfg->dyn_call_var) {
12229                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12230                                         /* prevent it from being register allocated */
12231                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12232                                 }
12233
12234                                 /* Has to use a call inst since it local regalloc expects it */
12235                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12236                                 ins = (MonoInst*)call;
12237                                 sp -= 2;
12238                                 ins->sreg1 = sp [0]->dreg;
12239                                 ins->sreg2 = sp [1]->dreg;
12240                                 MONO_ADD_INS (bblock, ins);
12241
12242                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12243
12244                                 ip += 2;
12245                                 inline_costs += 10 * num_calls++;
12246
12247                                 break;
12248                         }
12249                         case CEE_MONO_MEMORY_BARRIER: {
12250                                 CHECK_OPSIZE (6);
12251                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12252                                 ip += 6;
12253                                 break;
12254                         }
12255                         case CEE_MONO_JIT_ATTACH: {
12256                                 MonoInst *args [16], *domain_ins;
12257                                 MonoInst *ad_ins, *jit_tls_ins;
12258                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12259
12260                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12261
12262                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12263                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12264
12265                                 ad_ins = mono_get_domain_intrinsic (cfg);
12266                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12267
12268                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12269                                         NEW_BBLOCK (cfg, next_bb);
12270                                         NEW_BBLOCK (cfg, call_bb);
12271
12272                                         if (cfg->compile_aot) {
12273                                                 /* AOT code is only used in the root domain */
12274                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12275                                         } else {
12276                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12277                                         }
12278                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12279                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12280                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12281
12282                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12283                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12284                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12285
12286                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12287                                         MONO_START_BB (cfg, call_bb);
12288                                 }
12289
12290                                 if (cfg->compile_aot) {
12291                                         /* AOT code is only used in the root domain */
12292                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12293                                 } else {
12294                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12295                                 }
12296                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12297                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12298
12299                                 if (next_bb) {
12300                                         MONO_START_BB (cfg, next_bb);
12301                                         bblock = cfg->cbb;
12302                                 }
12303                                 ip += 2;
12304                                 break;
12305                         }
12306                         case CEE_MONO_JIT_DETACH: {
12307                                 MonoInst *args [16];
12308
12309                                 /* Restore the original domain */
12310                                 dreg = alloc_ireg (cfg);
12311                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12312                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12313                                 ip += 2;
12314                                 break;
12315                         }
12316                         default:
12317                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12318                                 break;
12319                         }
12320                         break;
12321                 }
12322
12323                 case CEE_PREFIX1: {
12324                         CHECK_OPSIZE (2);
12325                         switch (ip [1]) {
12326                         case CEE_ARGLIST: {
12327                                 /* somewhat similar to LDTOKEN */
12328                                 MonoInst *addr, *vtvar;
12329                                 CHECK_STACK_OVF (1);
12330                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12331
12332                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12333                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12334
12335                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12336                                 ins->type = STACK_VTYPE;
12337                                 ins->klass = mono_defaults.argumenthandle_class;
12338                                 *sp++ = ins;
12339                                 ip += 2;
12340                                 break;
12341                         }
12342                         case CEE_CEQ:
12343                         case CEE_CGT:
12344                         case CEE_CGT_UN:
12345                         case CEE_CLT:
12346                         case CEE_CLT_UN: {
12347                                 MonoInst *cmp, *arg1, *arg2;
12348
12349                                 CHECK_STACK (2);
12350                                 sp -= 2;
12351                                 arg1 = sp [0];
12352                                 arg2 = sp [1];
12353
12354                                 /*
12355                                  * The following transforms:
12356                                  *    CEE_CEQ    into OP_CEQ
12357                                  *    CEE_CGT    into OP_CGT
12358                                  *    CEE_CGT_UN into OP_CGT_UN
12359                                  *    CEE_CLT    into OP_CLT
12360                                  *    CEE_CLT_UN into OP_CLT_UN
12361                                  */
12362                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12363
12364                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12365                                 cmp->sreg1 = arg1->dreg;
12366                                 cmp->sreg2 = arg2->dreg;
12367                                 type_from_op (cfg, cmp, arg1, arg2);
12368                                 CHECK_TYPE (cmp);
12369                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12370                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12371                                         cmp->opcode = OP_LCOMPARE;
12372                                 else if (arg1->type == STACK_R4)
12373                                         cmp->opcode = OP_RCOMPARE;
12374                                 else if (arg1->type == STACK_R8)
12375                                         cmp->opcode = OP_FCOMPARE;
12376                                 else
12377                                         cmp->opcode = OP_ICOMPARE;
12378                                 MONO_ADD_INS (bblock, cmp);
12379                                 ins->type = STACK_I4;
12380                                 ins->dreg = alloc_dreg (cfg, ins->type);
12381                                 type_from_op (cfg, ins, arg1, arg2);
12382
12383                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12384                                         /*
12385                                          * The backends expect the fceq opcodes to do the
12386                                          * comparison too.
12387                                          */
12388                                         ins->sreg1 = cmp->sreg1;
12389                                         ins->sreg2 = cmp->sreg2;
12390                                         NULLIFY_INS (cmp);
12391                                 }
12392                                 MONO_ADD_INS (bblock, ins);
12393                                 *sp++ = ins;
12394                                 ip += 2;
12395                                 break;
12396                         }
12397                         case CEE_LDFTN: {
12398                                 MonoInst *argconst;
12399                                 MonoMethod *cil_method;
12400
12401                                 CHECK_STACK_OVF (1);
12402                                 CHECK_OPSIZE (6);
12403                                 n = read32 (ip + 2);
12404                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12405                                 if (!cmethod || mono_loader_get_last_error ())
12406                                         LOAD_ERROR;
12407                                 mono_class_init (cmethod->klass);
12408
12409                                 mono_save_token_info (cfg, image, n, cmethod);
12410
12411                                 context_used = mini_method_check_context_used (cfg, cmethod);
12412
12413                                 cil_method = cmethod;
12414                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12415                                         METHOD_ACCESS_FAILURE (method, cil_method);
12416
12417                                 if (mono_security_cas_enabled ()) {
12418                                         if (check_linkdemand (cfg, method, cmethod))
12419                                                 INLINE_FAILURE ("linkdemand");
12420                                         CHECK_CFG_EXCEPTION;
12421                                 } else if (mono_security_core_clr_enabled ()) {
12422                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12423                                 }
12424
12425                                 /* 
12426                                  * Optimize the common case of ldftn+delegate creation
12427                                  */
12428                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12429                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12430                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12431                                                 MonoInst *target_ins, *handle_ins;
12432                                                 MonoMethod *invoke;
12433                                                 int invoke_context_used;
12434
12435                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12436                                                 if (!invoke || !mono_method_signature (invoke))
12437                                                         LOAD_ERROR;
12438
12439                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12440
12441                                                 target_ins = sp [-1];
12442
12443                                                 if (mono_security_core_clr_enabled ())
12444                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12445
12446                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12447                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12448                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12449                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12450                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12451                                                         }
12452                                                 }
12453
12454 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12455                                                 /* FIXME: SGEN support */
12456                                                 if (invoke_context_used == 0) {
12457                                                         ip += 6;
12458                                                         if (cfg->verbose_level > 3)
12459                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12460                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12461                                                                 sp --;
12462                                                                 *sp = handle_ins;
12463                                                                 CHECK_CFG_EXCEPTION;
12464                                                                 ip += 5;
12465                                                                 sp ++;
12466                                                                 break;
12467                                                         }
12468                                                         ip -= 6;
12469                                                 }
12470 #endif
12471                                         }
12472                                 }
12473
12474                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12475                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12476                                 *sp++ = ins;
12477                                 
12478                                 ip += 6;
12479                                 inline_costs += 10 * num_calls++;
12480                                 break;
12481                         }
12482                         case CEE_LDVIRTFTN: {
12483                                 MonoInst *args [2];
12484
12485                                 CHECK_STACK (1);
12486                                 CHECK_OPSIZE (6);
12487                                 n = read32 (ip + 2);
12488                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12489                                 if (!cmethod || mono_loader_get_last_error ())
12490                                         LOAD_ERROR;
12491                                 mono_class_init (cmethod->klass);
12492  
12493                                 context_used = mini_method_check_context_used (cfg, cmethod);
12494
12495                                 if (mono_security_cas_enabled ()) {
12496                                         if (check_linkdemand (cfg, method, cmethod))
12497                                                 INLINE_FAILURE ("linkdemand");
12498                                         CHECK_CFG_EXCEPTION;
12499                                 } else if (mono_security_core_clr_enabled ()) {
12500                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12501                                 }
12502
12503                                 /*
12504                                  * Optimize the common case of ldvirtftn+delegate creation
12505                                  */
12506                                 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)) {
12507                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12508                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12509                                                 MonoInst *target_ins, *handle_ins;
12510                                                 MonoMethod *invoke;
12511                                                 int invoke_context_used;
12512
12513                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12514                                                 if (!invoke || !mono_method_signature (invoke))
12515                                                         LOAD_ERROR;
12516
12517                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12518
12519                                                 target_ins = sp [-1];
12520
12521                                                 if (mono_security_core_clr_enabled ())
12522                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12523
12524 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12525                                                 /* FIXME: SGEN support */
12526                                                 if (invoke_context_used == 0) {
12527                                                         ip += 6;
12528                                                         if (cfg->verbose_level > 3)
12529                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12530                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12531                                                                 sp -= 2;
12532                                                                 *sp = handle_ins;
12533                                                                 CHECK_CFG_EXCEPTION;
12534                                                                 ip += 5;
12535                                                                 sp ++;
12536                                                                 break;
12537                                                         }
12538                                                         ip -= 6;
12539                                                 }
12540 #endif
12541                                         }
12542                                 }
12543
12544                                 --sp;
12545                                 args [0] = *sp;
12546
12547                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12548                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12549
12550                                 if (context_used)
12551                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12552                                 else
12553                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12554
12555                                 ip += 6;
12556                                 inline_costs += 10 * num_calls++;
12557                                 break;
12558                         }
12559                         case CEE_LDARG:
12560                                 CHECK_STACK_OVF (1);
12561                                 CHECK_OPSIZE (4);
12562                                 n = read16 (ip + 2);
12563                                 CHECK_ARG (n);
12564                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12565                                 *sp++ = ins;
12566                                 ip += 4;
12567                                 break;
12568                         case CEE_LDARGA:
12569                                 CHECK_STACK_OVF (1);
12570                                 CHECK_OPSIZE (4);
12571                                 n = read16 (ip + 2);
12572                                 CHECK_ARG (n);
12573                                 NEW_ARGLOADA (cfg, ins, n);
12574                                 MONO_ADD_INS (cfg->cbb, ins);
12575                                 *sp++ = ins;
12576                                 ip += 4;
12577                                 break;
12578                         case CEE_STARG:
12579                                 CHECK_STACK (1);
12580                                 --sp;
12581                                 CHECK_OPSIZE (4);
12582                                 n = read16 (ip + 2);
12583                                 CHECK_ARG (n);
12584                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12585                                         UNVERIFIED;
12586                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12587                                 ip += 4;
12588                                 break;
12589                         case CEE_LDLOC:
12590                                 CHECK_STACK_OVF (1);
12591                                 CHECK_OPSIZE (4);
12592                                 n = read16 (ip + 2);
12593                                 CHECK_LOCAL (n);
12594                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12595                                 *sp++ = ins;
12596                                 ip += 4;
12597                                 break;
12598                         case CEE_LDLOCA: {
12599                                 unsigned char *tmp_ip;
12600                                 CHECK_STACK_OVF (1);
12601                                 CHECK_OPSIZE (4);
12602                                 n = read16 (ip + 2);
12603                                 CHECK_LOCAL (n);
12604
12605                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12606                                         ip = tmp_ip;
12607                                         inline_costs += 1;
12608                                         break;
12609                                 }                       
12610                                 
12611                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12612                                 *sp++ = ins;
12613                                 ip += 4;
12614                                 break;
12615                         }
12616                         case CEE_STLOC:
12617                                 CHECK_STACK (1);
12618                                 --sp;
12619                                 CHECK_OPSIZE (4);
12620                                 n = read16 (ip + 2);
12621                                 CHECK_LOCAL (n);
12622                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12623                                         UNVERIFIED;
12624                                 emit_stloc_ir (cfg, sp, header, n);
12625                                 ip += 4;
12626                                 inline_costs += 1;
12627                                 break;
12628                         case CEE_LOCALLOC:
12629                                 CHECK_STACK (1);
12630                                 --sp;
12631                                 if (sp != stack_start) 
12632                                         UNVERIFIED;
12633                                 if (cfg->method != method) 
12634                                         /* 
12635                                          * Inlining this into a loop in a parent could lead to 
12636                                          * stack overflows which is different behavior than the
12637                                          * non-inlined case, thus disable inlining in this case.
12638                                          */
12639                                         INLINE_FAILURE("localloc");
12640
12641                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12642                                 ins->dreg = alloc_preg (cfg);
12643                                 ins->sreg1 = sp [0]->dreg;
12644                                 ins->type = STACK_PTR;
12645                                 MONO_ADD_INS (cfg->cbb, ins);
12646
12647                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12648                                 if (init_locals)
12649                                         ins->flags |= MONO_INST_INIT;
12650
12651                                 *sp++ = ins;
12652                                 ip += 2;
12653                                 break;
12654                         case CEE_ENDFILTER: {
12655                                 MonoExceptionClause *clause, *nearest;
12656                                 int cc, nearest_num;
12657
12658                                 CHECK_STACK (1);
12659                                 --sp;
12660                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12661                                         UNVERIFIED;
12662                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12663                                 ins->sreg1 = (*sp)->dreg;
12664                                 MONO_ADD_INS (bblock, ins);
12665                                 start_new_bblock = 1;
12666                                 ip += 2;
12667
12668                                 nearest = NULL;
12669                                 nearest_num = 0;
12670                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12671                                         clause = &header->clauses [cc];
12672                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12673                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12674                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12675                                                 nearest = clause;
12676                                                 nearest_num = cc;
12677                                         }
12678                                 }
12679                                 g_assert (nearest);
12680                                 if ((ip - header->code) != nearest->handler_offset)
12681                                         UNVERIFIED;
12682
12683                                 break;
12684                         }
12685                         case CEE_UNALIGNED_:
12686                                 ins_flag |= MONO_INST_UNALIGNED;
12687                                 /* FIXME: record alignment? we can assume 1 for now */
12688                                 CHECK_OPSIZE (3);
12689                                 ip += 3;
12690                                 break;
12691                         case CEE_VOLATILE_:
12692                                 ins_flag |= MONO_INST_VOLATILE;
12693                                 ip += 2;
12694                                 break;
12695                         case CEE_TAIL_:
12696                                 ins_flag   |= MONO_INST_TAILCALL;
12697                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12698                                 /* Can't inline tail calls at this time */
12699                                 inline_costs += 100000;
12700                                 ip += 2;
12701                                 break;
12702                         case CEE_INITOBJ:
12703                                 CHECK_STACK (1);
12704                                 --sp;
12705                                 CHECK_OPSIZE (6);
12706                                 token = read32 (ip + 2);
12707                                 klass = mini_get_class (method, token, generic_context);
12708                                 CHECK_TYPELOAD (klass);
12709                                 if (generic_class_is_reference_type (cfg, klass))
12710                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12711                                 else
12712                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12713                                 ip += 6;
12714                                 inline_costs += 1;
12715                                 break;
12716                         case CEE_CONSTRAINED_:
12717                                 CHECK_OPSIZE (6);
12718                                 token = read32 (ip + 2);
12719                                 constrained_call = mini_get_class (method, token, generic_context);
12720                                 CHECK_TYPELOAD (constrained_call);
12721                                 ip += 6;
12722                                 break;
12723                         case CEE_CPBLK:
12724                         case CEE_INITBLK: {
12725                                 MonoInst *iargs [3];
12726                                 CHECK_STACK (3);
12727                                 sp -= 3;
12728
12729                                 /* Skip optimized paths for volatile operations. */
12730                                 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)) {
12731                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12732                                 } 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)) {
12733                                         /* emit_memset only works when val == 0 */
12734                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12735                                 } else {
12736                                         MonoInst *call;
12737                                         iargs [0] = sp [0];
12738                                         iargs [1] = sp [1];
12739                                         iargs [2] = sp [2];
12740                                         if (ip [1] == CEE_CPBLK) {
12741                                                 /*
12742                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12743                                                  * and release barriers for cpblk. It is technically both a load and
12744                                                  * store operation, so it seems like that's the sensible thing to do.
12745                                                  *
12746                                                  * FIXME: We emit full barriers on both sides of the operation for
12747                                                  * simplicity. We should have a separate atomic memcpy method instead.
12748                                                  */
12749                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12750
12751                                                 if (ins_flag & MONO_INST_VOLATILE)
12752                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12753
12754                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12755                                                 call->flags |= ins_flag;
12756
12757                                                 if (ins_flag & MONO_INST_VOLATILE)
12758                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12759                                         } else {
12760                                                 MonoMethod *memset_method = get_memset_method ();
12761                                                 if (ins_flag & MONO_INST_VOLATILE) {
12762                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12763                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12764                                                 }
12765                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12766                                                 call->flags |= ins_flag;
12767                                         }
12768                                 }
12769                                 ip += 2;
12770                                 ins_flag = 0;
12771                                 inline_costs += 1;
12772                                 break;
12773                         }
12774                         case CEE_NO_:
12775                                 CHECK_OPSIZE (3);
12776                                 if (ip [2] & 0x1)
12777                                         ins_flag |= MONO_INST_NOTYPECHECK;
12778                                 if (ip [2] & 0x2)
12779                                         ins_flag |= MONO_INST_NORANGECHECK;
12780                                 /* we ignore the no-nullcheck for now since we
12781                                  * really do it explicitly only when doing callvirt->call
12782                                  */
12783                                 ip += 3;
12784                                 break;
12785                         case CEE_RETHROW: {
12786                                 MonoInst *load;
12787                                 int handler_offset = -1;
12788
12789                                 for (i = 0; i < header->num_clauses; ++i) {
12790                                         MonoExceptionClause *clause = &header->clauses [i];
12791                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12792                                                 handler_offset = clause->handler_offset;
12793                                                 break;
12794                                         }
12795                                 }
12796
12797                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12798
12799                                 if (handler_offset == -1)
12800                                         UNVERIFIED;
12801
12802                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12803                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12804                                 ins->sreg1 = load->dreg;
12805                                 MONO_ADD_INS (bblock, ins);
12806
12807                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12808                                 MONO_ADD_INS (bblock, ins);
12809
12810                                 sp = stack_start;
12811                                 link_bblock (cfg, bblock, end_bblock);
12812                                 start_new_bblock = 1;
12813                                 ip += 2;
12814                                 break;
12815                         }
12816                         case CEE_SIZEOF: {
12817                                 guint32 val;
12818                                 int ialign;
12819
12820                                 CHECK_STACK_OVF (1);
12821                                 CHECK_OPSIZE (6);
12822                                 token = read32 (ip + 2);
12823                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12824                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12825                                         CHECK_CFG_ERROR;
12826
12827                                         val = mono_type_size (type, &ialign);
12828                                 } else {
12829                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12830                                         CHECK_TYPELOAD (klass);
12831
12832                                         val = mono_type_size (&klass->byval_arg, &ialign);
12833
12834                                         if (mini_is_gsharedvt_klass (cfg, klass))
12835                                                 GSHAREDVT_FAILURE (*ip);
12836                                 }
12837                                 EMIT_NEW_ICONST (cfg, ins, val);
12838                                 *sp++= ins;
12839                                 ip += 6;
12840                                 break;
12841                         }
12842                         case CEE_REFANYTYPE: {
12843                                 MonoInst *src_var, *src;
12844
12845                                 GSHAREDVT_FAILURE (*ip);
12846
12847                                 CHECK_STACK (1);
12848                                 --sp;
12849
12850                                 // FIXME:
12851                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12852                                 if (!src_var)
12853                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12854                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12855                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12856                                 *sp++ = ins;
12857                                 ip += 2;
12858                                 break;
12859                         }
12860                         case CEE_READONLY_:
12861                                 readonly = TRUE;
12862                                 ip += 2;
12863                                 break;
12864
12865                         case CEE_UNUSED56:
12866                         case CEE_UNUSED57:
12867                         case CEE_UNUSED70:
12868                         case CEE_UNUSED:
12869                         case CEE_UNUSED99:
12870                                 UNVERIFIED;
12871                                 
12872                         default:
12873                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12874                                 UNVERIFIED;
12875                         }
12876                         break;
12877                 }
12878                 case CEE_UNUSED58:
12879                 case CEE_UNUSED1:
12880                         UNVERIFIED;
12881
12882                 default:
12883                         g_warning ("opcode 0x%02x not handled", *ip);
12884                         UNVERIFIED;
12885                 }
12886         }
12887         if (start_new_bblock != 1)
12888                 UNVERIFIED;
12889
12890         bblock->cil_length = ip - bblock->cil_code;
12891         if (bblock->next_bb) {
12892                 /* This could already be set because of inlining, #693905 */
12893                 MonoBasicBlock *bb = bblock;
12894
12895                 while (bb->next_bb)
12896                         bb = bb->next_bb;
12897                 bb->next_bb = end_bblock;
12898         } else {
12899                 bblock->next_bb = end_bblock;
12900         }
12901
12902         if (cfg->method == method && cfg->domainvar) {
12903                 MonoInst *store;
12904                 MonoInst *get_domain;
12905
12906                 cfg->cbb = init_localsbb;
12907
12908                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12909                         MONO_ADD_INS (cfg->cbb, get_domain);
12910                 } else {
12911                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12912                 }
12913                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12914                 MONO_ADD_INS (cfg->cbb, store);
12915         }
12916
12917 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12918         if (cfg->compile_aot)
12919                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12920                 mono_get_got_var (cfg);
12921 #endif
12922
12923         if (cfg->method == method && cfg->got_var)
12924                 mono_emit_load_got_addr (cfg);
12925
12926         if (init_localsbb) {
12927                 cfg->cbb = init_localsbb;
12928                 cfg->ip = NULL;
12929                 for (i = 0; i < header->num_locals; ++i) {
12930                         emit_init_local (cfg, i, header->locals [i], init_locals);
12931                 }
12932         }
12933
12934         if (cfg->init_ref_vars && cfg->method == method) {
12935                 /* Emit initialization for ref vars */
12936                 // FIXME: Avoid duplication initialization for IL locals.
12937                 for (i = 0; i < cfg->num_varinfo; ++i) {
12938                         MonoInst *ins = cfg->varinfo [i];
12939
12940                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12941                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12942                 }
12943         }
12944
12945         if (cfg->lmf_var && cfg->method == method) {
12946                 cfg->cbb = init_localsbb;
12947                 emit_push_lmf (cfg);
12948         }
12949
12950         cfg->cbb = init_localsbb;
12951         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12952
12953         if (seq_points) {
12954                 MonoBasicBlock *bb;
12955
12956                 /*
12957                  * Make seq points at backward branch targets interruptable.
12958                  */
12959                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12960                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12961                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12962         }
12963
12964         /* Add a sequence point for method entry/exit events */
12965         if (cfg->gen_seq_points_debug_data) {
12966                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12967                 MONO_ADD_INS (init_localsbb, ins);
12968                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12969                 MONO_ADD_INS (cfg->bb_exit, ins);
12970         }
12971
12972         /*
12973          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12974          * the code they refer to was dead (#11880).
12975          */
12976         if (sym_seq_points) {
12977                 for (i = 0; i < header->code_size; ++i) {
12978                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12979                                 MonoInst *ins;
12980
12981                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12982                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12983                         }
12984                 }
12985         }
12986
12987         cfg->ip = NULL;
12988
12989         if (cfg->method == method) {
12990                 MonoBasicBlock *bb;
12991                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12992                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12993                         if (cfg->spvars)
12994                                 mono_create_spvar_for_region (cfg, bb->region);
12995                         if (cfg->verbose_level > 2)
12996                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12997                 }
12998         }
12999
13000         if (inline_costs < 0) {
13001                 char *mname;
13002
13003                 /* Method is too large */
13004                 mname = mono_method_full_name (method, TRUE);
13005                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13006                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13007                 g_free (mname);
13008         }
13009
13010         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13011                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13012
13013         goto cleanup;
13014
13015 mono_error_exit:
13016         g_assert (!mono_error_ok (&cfg->error));
13017         goto cleanup;
13018  
13019  exception_exit:
13020         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13021         goto cleanup;
13022
13023  unverified:
13024         set_exception_type_from_invalid_il (cfg, method, ip);
13025         goto cleanup;
13026
13027  cleanup:
13028         g_slist_free (class_inits);
13029         mono_basic_block_free (original_bb);
13030         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13031         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13032         if (cfg->exception_type)
13033                 return -1;
13034         else
13035                 return inline_costs;
13036 }
13037
13038 static int
13039 store_membase_reg_to_store_membase_imm (int opcode)
13040 {
13041         switch (opcode) {
13042         case OP_STORE_MEMBASE_REG:
13043                 return OP_STORE_MEMBASE_IMM;
13044         case OP_STOREI1_MEMBASE_REG:
13045                 return OP_STOREI1_MEMBASE_IMM;
13046         case OP_STOREI2_MEMBASE_REG:
13047                 return OP_STOREI2_MEMBASE_IMM;
13048         case OP_STOREI4_MEMBASE_REG:
13049                 return OP_STOREI4_MEMBASE_IMM;
13050         case OP_STOREI8_MEMBASE_REG:
13051                 return OP_STOREI8_MEMBASE_IMM;
13052         default:
13053                 g_assert_not_reached ();
13054         }
13055
13056         return -1;
13057 }               
13058
13059 int
13060 mono_op_to_op_imm (int opcode)
13061 {
13062         switch (opcode) {
13063         case OP_IADD:
13064                 return OP_IADD_IMM;
13065         case OP_ISUB:
13066                 return OP_ISUB_IMM;
13067         case OP_IDIV:
13068                 return OP_IDIV_IMM;
13069         case OP_IDIV_UN:
13070                 return OP_IDIV_UN_IMM;
13071         case OP_IREM:
13072                 return OP_IREM_IMM;
13073         case OP_IREM_UN:
13074                 return OP_IREM_UN_IMM;
13075         case OP_IMUL:
13076                 return OP_IMUL_IMM;
13077         case OP_IAND:
13078                 return OP_IAND_IMM;
13079         case OP_IOR:
13080                 return OP_IOR_IMM;
13081         case OP_IXOR:
13082                 return OP_IXOR_IMM;
13083         case OP_ISHL:
13084                 return OP_ISHL_IMM;
13085         case OP_ISHR:
13086                 return OP_ISHR_IMM;
13087         case OP_ISHR_UN:
13088                 return OP_ISHR_UN_IMM;
13089
13090         case OP_LADD:
13091                 return OP_LADD_IMM;
13092         case OP_LSUB:
13093                 return OP_LSUB_IMM;
13094         case OP_LAND:
13095                 return OP_LAND_IMM;
13096         case OP_LOR:
13097                 return OP_LOR_IMM;
13098         case OP_LXOR:
13099                 return OP_LXOR_IMM;
13100         case OP_LSHL:
13101                 return OP_LSHL_IMM;
13102         case OP_LSHR:
13103                 return OP_LSHR_IMM;
13104         case OP_LSHR_UN:
13105                 return OP_LSHR_UN_IMM;
13106 #if SIZEOF_REGISTER == 8
13107         case OP_LREM:
13108                 return OP_LREM_IMM;
13109 #endif
13110
13111         case OP_COMPARE:
13112                 return OP_COMPARE_IMM;
13113         case OP_ICOMPARE:
13114                 return OP_ICOMPARE_IMM;
13115         case OP_LCOMPARE:
13116                 return OP_LCOMPARE_IMM;
13117
13118         case OP_STORE_MEMBASE_REG:
13119                 return OP_STORE_MEMBASE_IMM;
13120         case OP_STOREI1_MEMBASE_REG:
13121                 return OP_STOREI1_MEMBASE_IMM;
13122         case OP_STOREI2_MEMBASE_REG:
13123                 return OP_STOREI2_MEMBASE_IMM;
13124         case OP_STOREI4_MEMBASE_REG:
13125                 return OP_STOREI4_MEMBASE_IMM;
13126
13127 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13128         case OP_X86_PUSH:
13129                 return OP_X86_PUSH_IMM;
13130         case OP_X86_COMPARE_MEMBASE_REG:
13131                 return OP_X86_COMPARE_MEMBASE_IMM;
13132 #endif
13133 #if defined(TARGET_AMD64)
13134         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13135                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13136 #endif
13137         case OP_VOIDCALL_REG:
13138                 return OP_VOIDCALL;
13139         case OP_CALL_REG:
13140                 return OP_CALL;
13141         case OP_LCALL_REG:
13142                 return OP_LCALL;
13143         case OP_FCALL_REG:
13144                 return OP_FCALL;
13145         case OP_LOCALLOC:
13146                 return OP_LOCALLOC_IMM;
13147         }
13148
13149         return -1;
13150 }
13151
13152 static int
13153 ldind_to_load_membase (int opcode)
13154 {
13155         switch (opcode) {
13156         case CEE_LDIND_I1:
13157                 return OP_LOADI1_MEMBASE;
13158         case CEE_LDIND_U1:
13159                 return OP_LOADU1_MEMBASE;
13160         case CEE_LDIND_I2:
13161                 return OP_LOADI2_MEMBASE;
13162         case CEE_LDIND_U2:
13163                 return OP_LOADU2_MEMBASE;
13164         case CEE_LDIND_I4:
13165                 return OP_LOADI4_MEMBASE;
13166         case CEE_LDIND_U4:
13167                 return OP_LOADU4_MEMBASE;
13168         case CEE_LDIND_I:
13169                 return OP_LOAD_MEMBASE;
13170         case CEE_LDIND_REF:
13171                 return OP_LOAD_MEMBASE;
13172         case CEE_LDIND_I8:
13173                 return OP_LOADI8_MEMBASE;
13174         case CEE_LDIND_R4:
13175                 return OP_LOADR4_MEMBASE;
13176         case CEE_LDIND_R8:
13177                 return OP_LOADR8_MEMBASE;
13178         default:
13179                 g_assert_not_reached ();
13180         }
13181
13182         return -1;
13183 }
13184
13185 static int
13186 stind_to_store_membase (int opcode)
13187 {
13188         switch (opcode) {
13189         case CEE_STIND_I1:
13190                 return OP_STOREI1_MEMBASE_REG;
13191         case CEE_STIND_I2:
13192                 return OP_STOREI2_MEMBASE_REG;
13193         case CEE_STIND_I4:
13194                 return OP_STOREI4_MEMBASE_REG;
13195         case CEE_STIND_I:
13196         case CEE_STIND_REF:
13197                 return OP_STORE_MEMBASE_REG;
13198         case CEE_STIND_I8:
13199                 return OP_STOREI8_MEMBASE_REG;
13200         case CEE_STIND_R4:
13201                 return OP_STORER4_MEMBASE_REG;
13202         case CEE_STIND_R8:
13203                 return OP_STORER8_MEMBASE_REG;
13204         default:
13205                 g_assert_not_reached ();
13206         }
13207
13208         return -1;
13209 }
13210
13211 int
13212 mono_load_membase_to_load_mem (int opcode)
13213 {
13214         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13215 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13216         switch (opcode) {
13217         case OP_LOAD_MEMBASE:
13218                 return OP_LOAD_MEM;
13219         case OP_LOADU1_MEMBASE:
13220                 return OP_LOADU1_MEM;
13221         case OP_LOADU2_MEMBASE:
13222                 return OP_LOADU2_MEM;
13223         case OP_LOADI4_MEMBASE:
13224                 return OP_LOADI4_MEM;
13225         case OP_LOADU4_MEMBASE:
13226                 return OP_LOADU4_MEM;
13227 #if SIZEOF_REGISTER == 8
13228         case OP_LOADI8_MEMBASE:
13229                 return OP_LOADI8_MEM;
13230 #endif
13231         }
13232 #endif
13233
13234         return -1;
13235 }
13236
13237 static inline int
13238 op_to_op_dest_membase (int store_opcode, int opcode)
13239 {
13240 #if defined(TARGET_X86)
13241         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13242                 return -1;
13243
13244         switch (opcode) {
13245         case OP_IADD:
13246                 return OP_X86_ADD_MEMBASE_REG;
13247         case OP_ISUB:
13248                 return OP_X86_SUB_MEMBASE_REG;
13249         case OP_IAND:
13250                 return OP_X86_AND_MEMBASE_REG;
13251         case OP_IOR:
13252                 return OP_X86_OR_MEMBASE_REG;
13253         case OP_IXOR:
13254                 return OP_X86_XOR_MEMBASE_REG;
13255         case OP_ADD_IMM:
13256         case OP_IADD_IMM:
13257                 return OP_X86_ADD_MEMBASE_IMM;
13258         case OP_SUB_IMM:
13259         case OP_ISUB_IMM:
13260                 return OP_X86_SUB_MEMBASE_IMM;
13261         case OP_AND_IMM:
13262         case OP_IAND_IMM:
13263                 return OP_X86_AND_MEMBASE_IMM;
13264         case OP_OR_IMM:
13265         case OP_IOR_IMM:
13266                 return OP_X86_OR_MEMBASE_IMM;
13267         case OP_XOR_IMM:
13268         case OP_IXOR_IMM:
13269                 return OP_X86_XOR_MEMBASE_IMM;
13270         case OP_MOVE:
13271                 return OP_NOP;
13272         }
13273 #endif
13274
13275 #if defined(TARGET_AMD64)
13276         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13277                 return -1;
13278
13279         switch (opcode) {
13280         case OP_IADD:
13281                 return OP_X86_ADD_MEMBASE_REG;
13282         case OP_ISUB:
13283                 return OP_X86_SUB_MEMBASE_REG;
13284         case OP_IAND:
13285                 return OP_X86_AND_MEMBASE_REG;
13286         case OP_IOR:
13287                 return OP_X86_OR_MEMBASE_REG;
13288         case OP_IXOR:
13289                 return OP_X86_XOR_MEMBASE_REG;
13290         case OP_IADD_IMM:
13291                 return OP_X86_ADD_MEMBASE_IMM;
13292         case OP_ISUB_IMM:
13293                 return OP_X86_SUB_MEMBASE_IMM;
13294         case OP_IAND_IMM:
13295                 return OP_X86_AND_MEMBASE_IMM;
13296         case OP_IOR_IMM:
13297                 return OP_X86_OR_MEMBASE_IMM;
13298         case OP_IXOR_IMM:
13299                 return OP_X86_XOR_MEMBASE_IMM;
13300         case OP_LADD:
13301                 return OP_AMD64_ADD_MEMBASE_REG;
13302         case OP_LSUB:
13303                 return OP_AMD64_SUB_MEMBASE_REG;
13304         case OP_LAND:
13305                 return OP_AMD64_AND_MEMBASE_REG;
13306         case OP_LOR:
13307                 return OP_AMD64_OR_MEMBASE_REG;
13308         case OP_LXOR:
13309                 return OP_AMD64_XOR_MEMBASE_REG;
13310         case OP_ADD_IMM:
13311         case OP_LADD_IMM:
13312                 return OP_AMD64_ADD_MEMBASE_IMM;
13313         case OP_SUB_IMM:
13314         case OP_LSUB_IMM:
13315                 return OP_AMD64_SUB_MEMBASE_IMM;
13316         case OP_AND_IMM:
13317         case OP_LAND_IMM:
13318                 return OP_AMD64_AND_MEMBASE_IMM;
13319         case OP_OR_IMM:
13320         case OP_LOR_IMM:
13321                 return OP_AMD64_OR_MEMBASE_IMM;
13322         case OP_XOR_IMM:
13323         case OP_LXOR_IMM:
13324                 return OP_AMD64_XOR_MEMBASE_IMM;
13325         case OP_MOVE:
13326                 return OP_NOP;
13327         }
13328 #endif
13329
13330         return -1;
13331 }
13332
13333 static inline int
13334 op_to_op_store_membase (int store_opcode, int opcode)
13335 {
13336 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13337         switch (opcode) {
13338         case OP_ICEQ:
13339                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13340                         return OP_X86_SETEQ_MEMBASE;
13341         case OP_CNE:
13342                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13343                         return OP_X86_SETNE_MEMBASE;
13344         }
13345 #endif
13346
13347         return -1;
13348 }
13349
13350 static inline int
13351 op_to_op_src1_membase (int load_opcode, int opcode)
13352 {
13353 #ifdef TARGET_X86
13354         /* FIXME: This has sign extension issues */
13355         /*
13356         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13357                 return OP_X86_COMPARE_MEMBASE8_IMM;
13358         */
13359
13360         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13361                 return -1;
13362
13363         switch (opcode) {
13364         case OP_X86_PUSH:
13365                 return OP_X86_PUSH_MEMBASE;
13366         case OP_COMPARE_IMM:
13367         case OP_ICOMPARE_IMM:
13368                 return OP_X86_COMPARE_MEMBASE_IMM;
13369         case OP_COMPARE:
13370         case OP_ICOMPARE:
13371                 return OP_X86_COMPARE_MEMBASE_REG;
13372         }
13373 #endif
13374
13375 #ifdef TARGET_AMD64
13376         /* FIXME: This has sign extension issues */
13377         /*
13378         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13379                 return OP_X86_COMPARE_MEMBASE8_IMM;
13380         */
13381
13382         switch (opcode) {
13383         case OP_X86_PUSH:
13384 #ifdef __mono_ilp32__
13385                 if (load_opcode == OP_LOADI8_MEMBASE)
13386 #else
13387                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13388 #endif
13389                         return OP_X86_PUSH_MEMBASE;
13390                 break;
13391                 /* FIXME: This only works for 32 bit immediates
13392         case OP_COMPARE_IMM:
13393         case OP_LCOMPARE_IMM:
13394                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13395                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13396                 */
13397         case OP_ICOMPARE_IMM:
13398                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13399                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13400                 break;
13401         case OP_COMPARE:
13402         case OP_LCOMPARE:
13403 #ifdef __mono_ilp32__
13404                 if (load_opcode == OP_LOAD_MEMBASE)
13405                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13406                 if (load_opcode == OP_LOADI8_MEMBASE)
13407 #else
13408                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13409 #endif
13410                         return OP_AMD64_COMPARE_MEMBASE_REG;
13411                 break;
13412         case OP_ICOMPARE:
13413                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13414                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13415                 break;
13416         }
13417 #endif
13418
13419         return -1;
13420 }
13421
13422 static inline int
13423 op_to_op_src2_membase (int load_opcode, int opcode)
13424 {
13425 #ifdef TARGET_X86
13426         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13427                 return -1;
13428         
13429         switch (opcode) {
13430         case OP_COMPARE:
13431         case OP_ICOMPARE:
13432                 return OP_X86_COMPARE_REG_MEMBASE;
13433         case OP_IADD:
13434                 return OP_X86_ADD_REG_MEMBASE;
13435         case OP_ISUB:
13436                 return OP_X86_SUB_REG_MEMBASE;
13437         case OP_IAND:
13438                 return OP_X86_AND_REG_MEMBASE;
13439         case OP_IOR:
13440                 return OP_X86_OR_REG_MEMBASE;
13441         case OP_IXOR:
13442                 return OP_X86_XOR_REG_MEMBASE;
13443         }
13444 #endif
13445
13446 #ifdef TARGET_AMD64
13447 #ifdef __mono_ilp32__
13448         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13449 #else
13450         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13451 #endif
13452                 switch (opcode) {
13453                 case OP_ICOMPARE:
13454                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13455                 case OP_IADD:
13456                         return OP_X86_ADD_REG_MEMBASE;
13457                 case OP_ISUB:
13458                         return OP_X86_SUB_REG_MEMBASE;
13459                 case OP_IAND:
13460                         return OP_X86_AND_REG_MEMBASE;
13461                 case OP_IOR:
13462                         return OP_X86_OR_REG_MEMBASE;
13463                 case OP_IXOR:
13464                         return OP_X86_XOR_REG_MEMBASE;
13465                 }
13466 #ifdef __mono_ilp32__
13467         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13468 #else
13469         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13470 #endif
13471                 switch (opcode) {
13472                 case OP_COMPARE:
13473                 case OP_LCOMPARE:
13474                         return OP_AMD64_COMPARE_REG_MEMBASE;
13475                 case OP_LADD:
13476                         return OP_AMD64_ADD_REG_MEMBASE;
13477                 case OP_LSUB:
13478                         return OP_AMD64_SUB_REG_MEMBASE;
13479                 case OP_LAND:
13480                         return OP_AMD64_AND_REG_MEMBASE;
13481                 case OP_LOR:
13482                         return OP_AMD64_OR_REG_MEMBASE;
13483                 case OP_LXOR:
13484                         return OP_AMD64_XOR_REG_MEMBASE;
13485                 }
13486         }
13487 #endif
13488
13489         return -1;
13490 }
13491
13492 int
13493 mono_op_to_op_imm_noemul (int opcode)
13494 {
13495         switch (opcode) {
13496 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13497         case OP_LSHR:
13498         case OP_LSHL:
13499         case OP_LSHR_UN:
13500                 return -1;
13501 #endif
13502 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13503         case OP_IDIV:
13504         case OP_IDIV_UN:
13505         case OP_IREM:
13506         case OP_IREM_UN:
13507                 return -1;
13508 #endif
13509 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13510         case OP_IMUL:
13511                 return -1;
13512 #endif
13513         default:
13514                 return mono_op_to_op_imm (opcode);
13515         }
13516 }
13517
13518 /**
13519  * mono_handle_global_vregs:
13520  *
13521  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13522  * for them.
13523  */
13524 void
13525 mono_handle_global_vregs (MonoCompile *cfg)
13526 {
13527         gint32 *vreg_to_bb;
13528         MonoBasicBlock *bb;
13529         int i, pos;
13530
13531         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13532
13533 #ifdef MONO_ARCH_SIMD_INTRINSICS
13534         if (cfg->uses_simd_intrinsics)
13535                 mono_simd_simplify_indirection (cfg);
13536 #endif
13537
13538         /* Find local vregs used in more than one bb */
13539         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13540                 MonoInst *ins = bb->code;       
13541                 int block_num = bb->block_num;
13542
13543                 if (cfg->verbose_level > 2)
13544                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13545
13546                 cfg->cbb = bb;
13547                 for (; ins; ins = ins->next) {
13548                         const char *spec = INS_INFO (ins->opcode);
13549                         int regtype = 0, regindex;
13550                         gint32 prev_bb;
13551
13552                         if (G_UNLIKELY (cfg->verbose_level > 2))
13553                                 mono_print_ins (ins);
13554
13555                         g_assert (ins->opcode >= MONO_CEE_LAST);
13556
13557                         for (regindex = 0; regindex < 4; regindex ++) {
13558                                 int vreg = 0;
13559
13560                                 if (regindex == 0) {
13561                                         regtype = spec [MONO_INST_DEST];
13562                                         if (regtype == ' ')
13563                                                 continue;
13564                                         vreg = ins->dreg;
13565                                 } else if (regindex == 1) {
13566                                         regtype = spec [MONO_INST_SRC1];
13567                                         if (regtype == ' ')
13568                                                 continue;
13569                                         vreg = ins->sreg1;
13570                                 } else if (regindex == 2) {
13571                                         regtype = spec [MONO_INST_SRC2];
13572                                         if (regtype == ' ')
13573                                                 continue;
13574                                         vreg = ins->sreg2;
13575                                 } else if (regindex == 3) {
13576                                         regtype = spec [MONO_INST_SRC3];
13577                                         if (regtype == ' ')
13578                                                 continue;
13579                                         vreg = ins->sreg3;
13580                                 }
13581
13582 #if SIZEOF_REGISTER == 4
13583                                 /* In the LLVM case, the long opcodes are not decomposed */
13584                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13585                                         /*
13586                                          * Since some instructions reference the original long vreg,
13587                                          * and some reference the two component vregs, it is quite hard
13588                                          * to determine when it needs to be global. So be conservative.
13589                                          */
13590                                         if (!get_vreg_to_inst (cfg, vreg)) {
13591                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13592
13593                                                 if (cfg->verbose_level > 2)
13594                                                         printf ("LONG VREG R%d made global.\n", vreg);
13595                                         }
13596
13597                                         /*
13598                                          * Make the component vregs volatile since the optimizations can
13599                                          * get confused otherwise.
13600                                          */
13601                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13602                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13603                                 }
13604 #endif
13605
13606                                 g_assert (vreg != -1);
13607
13608                                 prev_bb = vreg_to_bb [vreg];
13609                                 if (prev_bb == 0) {
13610                                         /* 0 is a valid block num */
13611                                         vreg_to_bb [vreg] = block_num + 1;
13612                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13613                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13614                                                 continue;
13615
13616                                         if (!get_vreg_to_inst (cfg, vreg)) {
13617                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13618                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13619
13620                                                 switch (regtype) {
13621                                                 case 'i':
13622                                                         if (vreg_is_ref (cfg, vreg))
13623                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13624                                                         else
13625                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13626                                                         break;
13627                                                 case 'l':
13628                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13629                                                         break;
13630                                                 case 'f':
13631                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13632                                                         break;
13633                                                 case 'v':
13634                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13635                                                         break;
13636                                                 default:
13637                                                         g_assert_not_reached ();
13638                                                 }
13639                                         }
13640
13641                                         /* Flag as having been used in more than one bb */
13642                                         vreg_to_bb [vreg] = -1;
13643                                 }
13644                         }
13645                 }
13646         }
13647
13648         /* If a variable is used in only one bblock, convert it into a local vreg */
13649         for (i = 0; i < cfg->num_varinfo; i++) {
13650                 MonoInst *var = cfg->varinfo [i];
13651                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13652
13653                 switch (var->type) {
13654                 case STACK_I4:
13655                 case STACK_OBJ:
13656                 case STACK_PTR:
13657                 case STACK_MP:
13658                 case STACK_VTYPE:
13659 #if SIZEOF_REGISTER == 8
13660                 case STACK_I8:
13661 #endif
13662 #if !defined(TARGET_X86)
13663                 /* Enabling this screws up the fp stack on x86 */
13664                 case STACK_R8:
13665 #endif
13666                         if (mono_arch_is_soft_float ())
13667                                 break;
13668
13669                         /* Arguments are implicitly global */
13670                         /* Putting R4 vars into registers doesn't work currently */
13671                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13672                         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) {
13673                                 /* 
13674                                  * Make that the variable's liveness interval doesn't contain a call, since
13675                                  * that would cause the lvreg to be spilled, making the whole optimization
13676                                  * useless.
13677                                  */
13678                                 /* This is too slow for JIT compilation */
13679 #if 0
13680                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13681                                         MonoInst *ins;
13682                                         int def_index, call_index, ins_index;
13683                                         gboolean spilled = FALSE;
13684
13685                                         def_index = -1;
13686                                         call_index = -1;
13687                                         ins_index = 0;
13688                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13689                                                 const char *spec = INS_INFO (ins->opcode);
13690
13691                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13692                                                         def_index = ins_index;
13693
13694                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13695                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13696                                                         if (call_index > def_index) {
13697                                                                 spilled = TRUE;
13698                                                                 break;
13699                                                         }
13700                                                 }
13701
13702                                                 if (MONO_IS_CALL (ins))
13703                                                         call_index = ins_index;
13704
13705                                                 ins_index ++;
13706                                         }
13707
13708                                         if (spilled)
13709                                                 break;
13710                                 }
13711 #endif
13712
13713                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13714                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13715                                 var->flags |= MONO_INST_IS_DEAD;
13716                                 cfg->vreg_to_inst [var->dreg] = NULL;
13717                         }
13718                         break;
13719                 }
13720         }
13721
13722         /* 
13723          * Compress the varinfo and vars tables so the liveness computation is faster and
13724          * takes up less space.
13725          */
13726         pos = 0;
13727         for (i = 0; i < cfg->num_varinfo; ++i) {
13728                 MonoInst *var = cfg->varinfo [i];
13729                 if (pos < i && cfg->locals_start == i)
13730                         cfg->locals_start = pos;
13731                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13732                         if (pos < i) {
13733                                 cfg->varinfo [pos] = cfg->varinfo [i];
13734                                 cfg->varinfo [pos]->inst_c0 = pos;
13735                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13736                                 cfg->vars [pos].idx = pos;
13737 #if SIZEOF_REGISTER == 4
13738                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13739                                         /* Modify the two component vars too */
13740                                         MonoInst *var1;
13741
13742                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13743                                         var1->inst_c0 = pos;
13744                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13745                                         var1->inst_c0 = pos;
13746                                 }
13747 #endif
13748                         }
13749                         pos ++;
13750                 }
13751         }
13752         cfg->num_varinfo = pos;
13753         if (cfg->locals_start > cfg->num_varinfo)
13754                 cfg->locals_start = cfg->num_varinfo;
13755 }
13756
13757 /**
13758  * mono_spill_global_vars:
13759  *
13760  *   Generate spill code for variables which are not allocated to registers, 
13761  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13762  * code is generated which could be optimized by the local optimization passes.
13763  */
13764 void
13765 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13766 {
13767         MonoBasicBlock *bb;
13768         char spec2 [16];
13769         int orig_next_vreg;
13770         guint32 *vreg_to_lvreg;
13771         guint32 *lvregs;
13772         guint32 i, lvregs_len;
13773         gboolean dest_has_lvreg = FALSE;
13774         guint32 stacktypes [128];
13775         MonoInst **live_range_start, **live_range_end;
13776         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13777         int *gsharedvt_vreg_to_idx = NULL;
13778
13779         *need_local_opts = FALSE;
13780
13781         memset (spec2, 0, sizeof (spec2));
13782
13783         /* FIXME: Move this function to mini.c */
13784         stacktypes ['i'] = STACK_PTR;
13785         stacktypes ['l'] = STACK_I8;
13786         stacktypes ['f'] = STACK_R8;
13787 #ifdef MONO_ARCH_SIMD_INTRINSICS
13788         stacktypes ['x'] = STACK_VTYPE;
13789 #endif
13790
13791 #if SIZEOF_REGISTER == 4
13792         /* Create MonoInsts for longs */
13793         for (i = 0; i < cfg->num_varinfo; i++) {
13794                 MonoInst *ins = cfg->varinfo [i];
13795
13796                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13797                         switch (ins->type) {
13798                         case STACK_R8:
13799                         case STACK_I8: {
13800                                 MonoInst *tree;
13801
13802                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13803                                         break;
13804
13805                                 g_assert (ins->opcode == OP_REGOFFSET);
13806
13807                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13808                                 g_assert (tree);
13809                                 tree->opcode = OP_REGOFFSET;
13810                                 tree->inst_basereg = ins->inst_basereg;
13811                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13812
13813                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13814                                 g_assert (tree);
13815                                 tree->opcode = OP_REGOFFSET;
13816                                 tree->inst_basereg = ins->inst_basereg;
13817                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13818                                 break;
13819                         }
13820                         default:
13821                                 break;
13822                         }
13823                 }
13824         }
13825 #endif
13826
13827         if (cfg->compute_gc_maps) {
13828                 /* registers need liveness info even for !non refs */
13829                 for (i = 0; i < cfg->num_varinfo; i++) {
13830                         MonoInst *ins = cfg->varinfo [i];
13831
13832                         if (ins->opcode == OP_REGVAR)
13833                                 ins->flags |= MONO_INST_GC_TRACK;
13834                 }
13835         }
13836
13837         if (cfg->gsharedvt) {
13838                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13839
13840                 for (i = 0; i < cfg->num_varinfo; ++i) {
13841                         MonoInst *ins = cfg->varinfo [i];
13842                         int idx;
13843
13844                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13845                                 if (i >= cfg->locals_start) {
13846                                         /* Local */
13847                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13848                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13849                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13850                                         ins->inst_imm = idx;
13851                                 } else {
13852                                         /* Arg */
13853                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13854                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13855                                 }
13856                         }
13857                 }
13858         }
13859                 
13860         /* FIXME: widening and truncation */
13861
13862         /*
13863          * As an optimization, when a variable allocated to the stack is first loaded into 
13864          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13865          * the variable again.
13866          */
13867         orig_next_vreg = cfg->next_vreg;
13868         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13869         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13870         lvregs_len = 0;
13871
13872         /* 
13873          * These arrays contain the first and last instructions accessing a given
13874          * variable.
13875          * Since we emit bblocks in the same order we process them here, and we
13876          * don't split live ranges, these will precisely describe the live range of
13877          * the variable, i.e. the instruction range where a valid value can be found
13878          * in the variables location.
13879          * The live range is computed using the liveness info computed by the liveness pass.
13880          * We can't use vmv->range, since that is an abstract live range, and we need
13881          * one which is instruction precise.
13882          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13883          */
13884         /* FIXME: Only do this if debugging info is requested */
13885         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13886         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13887         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13888         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13889         
13890         /* Add spill loads/stores */
13891         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13892                 MonoInst *ins;
13893
13894                 if (cfg->verbose_level > 2)
13895                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13896
13897                 /* Clear vreg_to_lvreg array */
13898                 for (i = 0; i < lvregs_len; i++)
13899                         vreg_to_lvreg [lvregs [i]] = 0;
13900                 lvregs_len = 0;
13901
13902                 cfg->cbb = bb;
13903                 MONO_BB_FOR_EACH_INS (bb, ins) {
13904                         const char *spec = INS_INFO (ins->opcode);
13905                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13906                         gboolean store, no_lvreg;
13907                         int sregs [MONO_MAX_SRC_REGS];
13908
13909                         if (G_UNLIKELY (cfg->verbose_level > 2))
13910                                 mono_print_ins (ins);
13911
13912                         if (ins->opcode == OP_NOP)
13913                                 continue;
13914
13915                         /* 
13916                          * We handle LDADDR here as well, since it can only be decomposed
13917                          * when variable addresses are known.
13918                          */
13919                         if (ins->opcode == OP_LDADDR) {
13920                                 MonoInst *var = ins->inst_p0;
13921
13922                                 if (var->opcode == OP_VTARG_ADDR) {
13923                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13924                                         MonoInst *vtaddr = var->inst_left;
13925                                         if (vtaddr->opcode == OP_REGVAR) {
13926                                                 ins->opcode = OP_MOVE;
13927                                                 ins->sreg1 = vtaddr->dreg;
13928                                         }
13929                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13930                                                 ins->opcode = OP_LOAD_MEMBASE;
13931                                                 ins->inst_basereg = vtaddr->inst_basereg;
13932                                                 ins->inst_offset = vtaddr->inst_offset;
13933                                         } else
13934                                                 NOT_IMPLEMENTED;
13935                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13936                                         /* gsharedvt arg passed by ref */
13937                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13938
13939                                         ins->opcode = OP_LOAD_MEMBASE;
13940                                         ins->inst_basereg = var->inst_basereg;
13941                                         ins->inst_offset = var->inst_offset;
13942                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13943                                         MonoInst *load, *load2, *load3;
13944                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13945                                         int reg1, reg2, reg3;
13946                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13947                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13948
13949                                         /*
13950                                          * gsharedvt local.
13951                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13952                                          */
13953
13954                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13955
13956                                         g_assert (info_var);
13957                                         g_assert (locals_var);
13958
13959                                         /* Mark the instruction used to compute the locals var as used */
13960                                         cfg->gsharedvt_locals_var_ins = NULL;
13961
13962                                         /* Load the offset */
13963                                         if (info_var->opcode == OP_REGOFFSET) {
13964                                                 reg1 = alloc_ireg (cfg);
13965                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13966                                         } else if (info_var->opcode == OP_REGVAR) {
13967                                                 load = NULL;
13968                                                 reg1 = info_var->dreg;
13969                                         } else {
13970                                                 g_assert_not_reached ();
13971                                         }
13972                                         reg2 = alloc_ireg (cfg);
13973                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13974                                         /* Load the locals area address */
13975                                         reg3 = alloc_ireg (cfg);
13976                                         if (locals_var->opcode == OP_REGOFFSET) {
13977                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13978                                         } else if (locals_var->opcode == OP_REGVAR) {
13979                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13980                                         } else {
13981                                                 g_assert_not_reached ();
13982                                         }
13983                                         /* Compute the address */
13984                                         ins->opcode = OP_PADD;
13985                                         ins->sreg1 = reg3;
13986                                         ins->sreg2 = reg2;
13987
13988                                         mono_bblock_insert_before_ins (bb, ins, load3);
13989                                         mono_bblock_insert_before_ins (bb, load3, load2);
13990                                         if (load)
13991                                                 mono_bblock_insert_before_ins (bb, load2, load);
13992                                 } else {
13993                                         g_assert (var->opcode == OP_REGOFFSET);
13994
13995                                         ins->opcode = OP_ADD_IMM;
13996                                         ins->sreg1 = var->inst_basereg;
13997                                         ins->inst_imm = var->inst_offset;
13998                                 }
13999
14000                                 *need_local_opts = TRUE;
14001                                 spec = INS_INFO (ins->opcode);
14002                         }
14003
14004                         if (ins->opcode < MONO_CEE_LAST) {
14005                                 mono_print_ins (ins);
14006                                 g_assert_not_reached ();
14007                         }
14008
14009                         /*
14010                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14011                          * src register.
14012                          * FIXME:
14013                          */
14014                         if (MONO_IS_STORE_MEMBASE (ins)) {
14015                                 tmp_reg = ins->dreg;
14016                                 ins->dreg = ins->sreg2;
14017                                 ins->sreg2 = tmp_reg;
14018                                 store = TRUE;
14019
14020                                 spec2 [MONO_INST_DEST] = ' ';
14021                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14022                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14023                                 spec2 [MONO_INST_SRC3] = ' ';
14024                                 spec = spec2;
14025                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14026                                 g_assert_not_reached ();
14027                         else
14028                                 store = FALSE;
14029                         no_lvreg = FALSE;
14030
14031                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14032                                 printf ("\t %.3s %d", spec, ins->dreg);
14033                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14034                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14035                                         printf (" %d", sregs [srcindex]);
14036                                 printf ("\n");
14037                         }
14038
14039                         /***************/
14040                         /*    DREG     */
14041                         /***************/
14042                         regtype = spec [MONO_INST_DEST];
14043                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14044                         prev_dreg = -1;
14045
14046                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14047                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14048                                 MonoInst *store_ins;
14049                                 int store_opcode;
14050                                 MonoInst *def_ins = ins;
14051                                 int dreg = ins->dreg; /* The original vreg */
14052
14053                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14054
14055                                 if (var->opcode == OP_REGVAR) {
14056                                         ins->dreg = var->dreg;
14057                                 } 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)) {
14058                                         /* 
14059                                          * Instead of emitting a load+store, use a _membase opcode.
14060                                          */
14061                                         g_assert (var->opcode == OP_REGOFFSET);
14062                                         if (ins->opcode == OP_MOVE) {
14063                                                 NULLIFY_INS (ins);
14064                                                 def_ins = NULL;
14065                                         } else {
14066                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14067                                                 ins->inst_basereg = var->inst_basereg;
14068                                                 ins->inst_offset = var->inst_offset;
14069                                                 ins->dreg = -1;
14070                                         }
14071                                         spec = INS_INFO (ins->opcode);
14072                                 } else {
14073                                         guint32 lvreg;
14074
14075                                         g_assert (var->opcode == OP_REGOFFSET);
14076
14077                                         prev_dreg = ins->dreg;
14078
14079                                         /* Invalidate any previous lvreg for this vreg */
14080                                         vreg_to_lvreg [ins->dreg] = 0;
14081
14082                                         lvreg = 0;
14083
14084                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14085                                                 regtype = 'l';
14086                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14087                                         }
14088
14089                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14090
14091 #if SIZEOF_REGISTER != 8
14092                                         if (regtype == 'l') {
14093                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14094                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14095                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14096                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14097                                                 def_ins = store_ins;
14098                                         }
14099                                         else
14100 #endif
14101                                         {
14102                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14103
14104                                                 /* Try to fuse the store into the instruction itself */
14105                                                 /* FIXME: Add more instructions */
14106                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14107                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14108                                                         ins->inst_imm = ins->inst_c0;
14109                                                         ins->inst_destbasereg = var->inst_basereg;
14110                                                         ins->inst_offset = var->inst_offset;
14111                                                         spec = INS_INFO (ins->opcode);
14112                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14113                                                         ins->opcode = store_opcode;
14114                                                         ins->inst_destbasereg = var->inst_basereg;
14115                                                         ins->inst_offset = var->inst_offset;
14116
14117                                                         no_lvreg = TRUE;
14118
14119                                                         tmp_reg = ins->dreg;
14120                                                         ins->dreg = ins->sreg2;
14121                                                         ins->sreg2 = tmp_reg;
14122                                                         store = TRUE;
14123
14124                                                         spec2 [MONO_INST_DEST] = ' ';
14125                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14126                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14127                                                         spec2 [MONO_INST_SRC3] = ' ';
14128                                                         spec = spec2;
14129                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14130                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14131                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14132                                                         ins->dreg = -1;
14133                                                         ins->inst_basereg = var->inst_basereg;
14134                                                         ins->inst_offset = var->inst_offset;
14135                                                         spec = INS_INFO (ins->opcode);
14136                                                 } else {
14137                                                         /* printf ("INS: "); mono_print_ins (ins); */
14138                                                         /* Create a store instruction */
14139                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14140
14141                                                         /* Insert it after the instruction */
14142                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14143
14144                                                         def_ins = store_ins;
14145
14146                                                         /* 
14147                                                          * We can't assign ins->dreg to var->dreg here, since the
14148                                                          * sregs could use it. So set a flag, and do it after
14149                                                          * the sregs.
14150                                                          */
14151                                                         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)))
14152                                                                 dest_has_lvreg = TRUE;
14153                                                 }
14154                                         }
14155                                 }
14156
14157                                 if (def_ins && !live_range_start [dreg]) {
14158                                         live_range_start [dreg] = def_ins;
14159                                         live_range_start_bb [dreg] = bb;
14160                                 }
14161
14162                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14163                                         MonoInst *tmp;
14164
14165                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14166                                         tmp->inst_c1 = dreg;
14167                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14168                                 }
14169                         }
14170
14171                         /************/
14172                         /*  SREGS   */
14173                         /************/
14174                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14175                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14176                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14177                                 sreg = sregs [srcindex];
14178
14179                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14180                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14181                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14182                                         MonoInst *use_ins = ins;
14183                                         MonoInst *load_ins;
14184                                         guint32 load_opcode;
14185
14186                                         if (var->opcode == OP_REGVAR) {
14187                                                 sregs [srcindex] = var->dreg;
14188                                                 //mono_inst_set_src_registers (ins, sregs);
14189                                                 live_range_end [sreg] = use_ins;
14190                                                 live_range_end_bb [sreg] = bb;
14191
14192                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14193                                                         MonoInst *tmp;
14194
14195                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14196                                                         /* var->dreg is a hreg */
14197                                                         tmp->inst_c1 = sreg;
14198                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14199                                                 }
14200
14201                                                 continue;
14202                                         }
14203
14204                                         g_assert (var->opcode == OP_REGOFFSET);
14205                                                 
14206                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14207
14208                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14209
14210                                         if (vreg_to_lvreg [sreg]) {
14211                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14212
14213                                                 /* The variable is already loaded to an lvreg */
14214                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14215                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14216                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14217                                                 //mono_inst_set_src_registers (ins, sregs);
14218                                                 continue;
14219                                         }
14220
14221                                         /* Try to fuse the load into the instruction */
14222                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14223                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14224                                                 sregs [0] = var->inst_basereg;
14225                                                 //mono_inst_set_src_registers (ins, sregs);
14226                                                 ins->inst_offset = var->inst_offset;
14227                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14228                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14229                                                 sregs [1] = var->inst_basereg;
14230                                                 //mono_inst_set_src_registers (ins, sregs);
14231                                                 ins->inst_offset = var->inst_offset;
14232                                         } else {
14233                                                 if (MONO_IS_REAL_MOVE (ins)) {
14234                                                         ins->opcode = OP_NOP;
14235                                                         sreg = ins->dreg;
14236                                                 } else {
14237                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14238
14239                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14240
14241                                                         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) {
14242                                                                 if (var->dreg == prev_dreg) {
14243                                                                         /*
14244                                                                          * sreg refers to the value loaded by the load
14245                                                                          * emitted below, but we need to use ins->dreg
14246                                                                          * since it refers to the store emitted earlier.
14247                                                                          */
14248                                                                         sreg = ins->dreg;
14249                                                                 }
14250                                                                 g_assert (sreg != -1);
14251                                                                 vreg_to_lvreg [var->dreg] = sreg;
14252                                                                 g_assert (lvregs_len < 1024);
14253                                                                 lvregs [lvregs_len ++] = var->dreg;
14254                                                         }
14255                                                 }
14256
14257                                                 sregs [srcindex] = sreg;
14258                                                 //mono_inst_set_src_registers (ins, sregs);
14259
14260 #if SIZEOF_REGISTER != 8
14261                                                 if (regtype == 'l') {
14262                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14263                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14264                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14265                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14266                                                         use_ins = load_ins;
14267                                                 }
14268                                                 else
14269 #endif
14270                                                 {
14271 #if SIZEOF_REGISTER == 4
14272                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14273 #endif
14274                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14275                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14276                                                         use_ins = load_ins;
14277                                                 }
14278                                         }
14279
14280                                         if (var->dreg < orig_next_vreg) {
14281                                                 live_range_end [var->dreg] = use_ins;
14282                                                 live_range_end_bb [var->dreg] = bb;
14283                                         }
14284
14285                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14286                                                 MonoInst *tmp;
14287
14288                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14289                                                 tmp->inst_c1 = var->dreg;
14290                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14291                                         }
14292                                 }
14293                         }
14294                         mono_inst_set_src_registers (ins, sregs);
14295
14296                         if (dest_has_lvreg) {
14297                                 g_assert (ins->dreg != -1);
14298                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14299                                 g_assert (lvregs_len < 1024);
14300                                 lvregs [lvregs_len ++] = prev_dreg;
14301                                 dest_has_lvreg = FALSE;
14302                         }
14303
14304                         if (store) {
14305                                 tmp_reg = ins->dreg;
14306                                 ins->dreg = ins->sreg2;
14307                                 ins->sreg2 = tmp_reg;
14308                         }
14309
14310                         if (MONO_IS_CALL (ins)) {
14311                                 /* Clear vreg_to_lvreg array */
14312                                 for (i = 0; i < lvregs_len; i++)
14313                                         vreg_to_lvreg [lvregs [i]] = 0;
14314                                 lvregs_len = 0;
14315                         } else if (ins->opcode == OP_NOP) {
14316                                 ins->dreg = -1;
14317                                 MONO_INST_NULLIFY_SREGS (ins);
14318                         }
14319
14320                         if (cfg->verbose_level > 2)
14321                                 mono_print_ins_index (1, ins);
14322                 }
14323
14324                 /* Extend the live range based on the liveness info */
14325                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14326                         for (i = 0; i < cfg->num_varinfo; i ++) {
14327                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14328
14329                                 if (vreg_is_volatile (cfg, vi->vreg))
14330                                         /* The liveness info is incomplete */
14331                                         continue;
14332
14333                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14334                                         /* Live from at least the first ins of this bb */
14335                                         live_range_start [vi->vreg] = bb->code;
14336                                         live_range_start_bb [vi->vreg] = bb;
14337                                 }
14338
14339                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14340                                         /* Live at least until the last ins of this bb */
14341                                         live_range_end [vi->vreg] = bb->last_ins;
14342                                         live_range_end_bb [vi->vreg] = bb;
14343                                 }
14344                         }
14345                 }
14346         }
14347         
14348 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14349         /*
14350          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14351          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14352          */
14353         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14354                 for (i = 0; i < cfg->num_varinfo; ++i) {
14355                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14356                         MonoInst *ins;
14357
14358                         if (live_range_start [vreg]) {
14359                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14360                                 ins->inst_c0 = i;
14361                                 ins->inst_c1 = vreg;
14362                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14363                         }
14364                         if (live_range_end [vreg]) {
14365                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14366                                 ins->inst_c0 = i;
14367                                 ins->inst_c1 = vreg;
14368                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14369                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14370                                 else
14371                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14372                         }
14373                 }
14374         }
14375 #endif
14376
14377         if (cfg->gsharedvt_locals_var_ins) {
14378                 /* Nullify if unused */
14379                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14380                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14381         }
14382
14383         g_free (live_range_start);
14384         g_free (live_range_end);
14385         g_free (live_range_start_bb);
14386         g_free (live_range_end_bb);
14387 }
14388
14389 /**
14390  * FIXME:
14391  * - use 'iadd' instead of 'int_add'
14392  * - handling ovf opcodes: decompose in method_to_ir.
14393  * - unify iregs/fregs
14394  *   -> partly done, the missing parts are:
14395  *   - a more complete unification would involve unifying the hregs as well, so
14396  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14397  *     would no longer map to the machine hregs, so the code generators would need to
14398  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14399  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14400  *     fp/non-fp branches speeds it up by about 15%.
14401  * - use sext/zext opcodes instead of shifts
14402  * - add OP_ICALL
14403  * - get rid of TEMPLOADs if possible and use vregs instead
14404  * - clean up usage of OP_P/OP_ opcodes
14405  * - cleanup usage of DUMMY_USE
14406  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14407  *   stack
14408  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14409  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14410  * - make sure handle_stack_args () is called before the branch is emitted
14411  * - when the new IR is done, get rid of all unused stuff
14412  * - COMPARE/BEQ as separate instructions or unify them ?
14413  *   - keeping them separate allows specialized compare instructions like
14414  *     compare_imm, compare_membase
14415  *   - most back ends unify fp compare+branch, fp compare+ceq
14416  * - integrate mono_save_args into inline_method
14417  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14418  * - handle long shift opts on 32 bit platforms somehow: they require 
14419  *   3 sregs (2 for arg1 and 1 for arg2)
14420  * - make byref a 'normal' type.
14421  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14422  *   variable if needed.
14423  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14424  *   like inline_method.
14425  * - remove inlining restrictions
14426  * - fix LNEG and enable cfold of INEG
14427  * - generalize x86 optimizations like ldelema as a peephole optimization
14428  * - add store_mem_imm for amd64
14429  * - optimize the loading of the interruption flag in the managed->native wrappers
14430  * - avoid special handling of OP_NOP in passes
14431  * - move code inserting instructions into one function/macro.
14432  * - try a coalescing phase after liveness analysis
14433  * - add float -> vreg conversion + local optimizations on !x86
14434  * - figure out how to handle decomposed branches during optimizations, ie.
14435  *   compare+branch, op_jump_table+op_br etc.
14436  * - promote RuntimeXHandles to vregs
14437  * - vtype cleanups:
14438  *   - add a NEW_VARLOADA_VREG macro
14439  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14440  *   accessing vtype fields.
14441  * - get rid of I8CONST on 64 bit platforms
14442  * - dealing with the increase in code size due to branches created during opcode
14443  *   decomposition:
14444  *   - use extended basic blocks
14445  *     - all parts of the JIT
14446  *     - handle_global_vregs () && local regalloc
14447  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14448  * - sources of increase in code size:
14449  *   - vtypes
14450  *   - long compares
14451  *   - isinst and castclass
14452  *   - lvregs not allocated to global registers even if used multiple times
14453  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14454  *   meaningful.
14455  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14456  * - add all micro optimizations from the old JIT
14457  * - put tree optimizations into the deadce pass
14458  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14459  *   specific function.
14460  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14461  *   fcompare + branchCC.
14462  * - create a helper function for allocating a stack slot, taking into account 
14463  *   MONO_CFG_HAS_SPILLUP.
14464  * - merge r68207.
14465  * - merge the ia64 switch changes.
14466  * - optimize mono_regstate2_alloc_int/float.
14467  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14468  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14469  *   parts of the tree could be separated by other instructions, killing the tree
14470  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14471  *   instructions if the result of the load is used multiple times ?
14472  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14473  * - LAST MERGE: 108395.
14474  * - when returning vtypes in registers, generate IR and append it to the end of the
14475  *   last bb instead of doing it in the epilog.
14476  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14477  */
14478
14479 /*
14480
14481 NOTES
14482 -----
14483
14484 - When to decompose opcodes:
14485   - earlier: this makes some optimizations hard to implement, since the low level IR
14486   no longer contains the neccessary information. But it is easier to do.
14487   - later: harder to implement, enables more optimizations.
14488 - Branches inside bblocks:
14489   - created when decomposing complex opcodes. 
14490     - branches to another bblock: harmless, but not tracked by the branch 
14491       optimizations, so need to branch to a label at the start of the bblock.
14492     - branches to inside the same bblock: very problematic, trips up the local
14493       reg allocator. Can be fixed by spitting the current bblock, but that is a
14494       complex operation, since some local vregs can become global vregs etc.
14495 - Local/global vregs:
14496   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14497     local register allocator.
14498   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14499     structure, created by mono_create_var (). Assigned to hregs or the stack by
14500     the global register allocator.
14501 - When to do optimizations like alu->alu_imm:
14502   - earlier -> saves work later on since the IR will be smaller/simpler
14503   - later -> can work on more instructions
14504 - Handling of valuetypes:
14505   - When a vtype is pushed on the stack, a new temporary is created, an 
14506     instruction computing its address (LDADDR) is emitted and pushed on
14507     the stack. Need to optimize cases when the vtype is used immediately as in
14508     argument passing, stloc etc.
14509 - Instead of the to_end stuff in the old JIT, simply call the function handling
14510   the values on the stack before emitting the last instruction of the bb.
14511 */
14512
14513 #endif /* DISABLE_JIT */