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