3f32e68f8655a0a211e564f3540640c1f25732ff
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/gc-internal.h>
53 #include <mono/metadata/security-manager.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/metadata/monitor.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_class_init_trampoline;
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
152 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
155 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
156 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
157
158 /*
159  * Instruction metadata
160  */
161 #ifdef MINI_OP
162 #undef MINI_OP
163 #endif
164 #ifdef MINI_OP3
165 #undef MINI_OP3
166 #endif
167 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
168 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
169 #define NONE ' '
170 #define IREG 'i'
171 #define FREG 'f'
172 #define VREG 'v'
173 #define XREG 'x'
174 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
175 #define LREG IREG
176 #else
177 #define LREG 'l'
178 #endif
179 /* keep in sync with the enum in mini.h */
180 const char
181 ins_info[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
188 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
189 /* 
190  * This should contain the index of the last sreg + 1. This is not the same
191  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
192  */
193 const gint8 ins_sreg_counts[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MONO_INIT_VARINFO(vi,id) do { \
200         (vi)->range.first_use.pos.bid = 0xffff; \
201         (vi)->reg = -1; \
202         (vi)->idx = (id); \
203 } while (0)
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_get_underlying_type (cfg, type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return mono_type_to_regmove (cfg, mini_get_underlying_type (cfg, type));
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
369 }
370
371 static MONO_NEVER_INLINE void
372 break_on_unverified (void)
373 {
374         if (mini_get_debug_options ()->break_on_unverified)
375                 G_BREAKPOINT ();
376 }
377
378 static MONO_NEVER_INLINE void
379 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
380 {
381         char *method_fname = mono_method_full_name (method, TRUE);
382         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
383         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
384         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
385         g_free (method_fname);
386         g_free (cil_method_fname);
387 }
388
389 static MONO_NEVER_INLINE void
390 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
391 {
392         char *method_fname = mono_method_full_name (method, TRUE);
393         char *field_fname = mono_field_full_name (field);
394         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
395         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
396         g_free (method_fname);
397         g_free (field_fname);
398 }
399
400 static MONO_NEVER_INLINE void
401 inline_failure (MonoCompile *cfg, const char *msg)
402 {
403         if (cfg->verbose_level >= 2)
404                 printf ("inline failed: %s\n", msg);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         if (cfg->verbose_level > 2)                                                                                     \
412                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
413         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
414 }
415
416 static MONO_NEVER_INLINE void
417 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
418 {
419         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
420         if (cfg->verbose_level >= 2)
421                 printf ("%s\n", cfg->exception_message);
422         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
423 }
424
425 /*
426  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
427  * foo<T> (int i) { ldarg.0; box T; }
428  */
429 #define UNVERIFIED do { \
430         if (cfg->gsharedvt) { \
431                 if (cfg->verbose_level > 2)                                                                     \
432                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
433                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
434                 goto exception_exit;                                                                                    \
435         }                                                                                                                                       \
436         break_on_unverified ();                                                                                         \
437         goto unverified;                                                                                                        \
438 } while (0)
439
440 #define GET_BBLOCK(cfg,tblock,ip) do {  \
441                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
442                 if (!(tblock)) {        \
443                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
444             NEW_BBLOCK (cfg, (tblock)); \
445                         (tblock)->cil_code = (ip);      \
446                         ADD_BBLOCK (cfg, (tblock));     \
447                 } \
448         } while (0)
449
450 #if defined(TARGET_X86) || defined(TARGET_AMD64)
451 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
452                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
453                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
454                 (dest)->sreg1 = (sr1); \
455                 (dest)->sreg2 = (sr2); \
456                 (dest)->inst_imm = (imm); \
457                 (dest)->backend.shift_amount = (shift); \
458                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
459         } while (0)
460 #endif
461
462 /* Emit conversions so both operands of a binary opcode are of the same type */
463 static void
464 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
465 {
466         MonoInst *arg1 = *arg1_ref;
467         MonoInst *arg2 = *arg2_ref;
468
469         if (cfg->r4fp &&
470                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
471                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
472                 MonoInst *conv;
473
474                 /* Mixing r4/r8 is allowed by the spec */
475                 if (arg1->type == STACK_R4) {
476                         int dreg = alloc_freg (cfg);
477
478                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
479                         conv->type = STACK_R8;
480                         ins->sreg1 = dreg;
481                         *arg1_ref = conv;
482                 }
483                 if (arg2->type == STACK_R4) {
484                         int dreg = alloc_freg (cfg);
485
486                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
487                         conv->type = STACK_R8;
488                         ins->sreg2 = dreg;
489                         *arg2_ref = conv;
490                 }
491         }
492
493 #if SIZEOF_REGISTER == 8
494         /* FIXME: Need to add many more cases */
495         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
496                 MonoInst *widen;
497
498                 int dr = alloc_preg (cfg);
499                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
500                 (ins)->sreg2 = widen->dreg;
501         }
502 #endif
503 }
504
505 #define ADD_BINOP(op) do {      \
506                 MONO_INST_NEW (cfg, ins, (op)); \
507                 sp -= 2;        \
508                 ins->sreg1 = sp [0]->dreg;      \
509                 ins->sreg2 = sp [1]->dreg;      \
510                 type_from_op (cfg, ins, sp [0], sp [1]);        \
511                 CHECK_TYPE (ins);       \
512                 /* Have to insert a widening op */               \
513         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
514         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
515         MONO_ADD_INS ((cfg)->cbb, (ins)); \
516         *sp++ = mono_decompose_opcode ((cfg), (ins), &bblock);  \
517         } while (0)
518
519 #define ADD_UNOP(op) do {       \
520                 MONO_INST_NEW (cfg, ins, (op)); \
521                 sp--;   \
522                 ins->sreg1 = sp [0]->dreg;      \
523                 type_from_op (cfg, ins, sp [0], NULL);  \
524                 CHECK_TYPE (ins);       \
525         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
526         MONO_ADD_INS ((cfg)->cbb, (ins)); \
527                 *sp++ = mono_decompose_opcode (cfg, ins, &bblock);      \
528         } while (0)
529
530 #define ADD_BINCOND(next_block) do {    \
531                 MonoInst *cmp;  \
532                 sp -= 2; \
533                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
534                 cmp->sreg1 = sp [0]->dreg;      \
535                 cmp->sreg2 = sp [1]->dreg;      \
536                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
537                 CHECK_TYPE (cmp);       \
538                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
539                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
540                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
541                 GET_BBLOCK (cfg, tblock, target);               \
542                 link_bblock (cfg, bblock, tblock);      \
543                 ins->inst_true_bb = tblock;     \
544                 if ((next_block)) {     \
545                         link_bblock (cfg, bblock, (next_block));        \
546                         ins->inst_false_bb = (next_block);      \
547                         start_new_bblock = 1;   \
548                 } else {        \
549                         GET_BBLOCK (cfg, tblock, ip);           \
550                         link_bblock (cfg, bblock, tblock);      \
551                         ins->inst_false_bb = tblock;    \
552                         start_new_bblock = 2;   \
553                 }       \
554                 if (sp != stack_start) {                                                                        \
555                     handle_stack_args (cfg, stack_start, sp - stack_start); \
556                         CHECK_UNVERIFIABLE (cfg); \
557                 } \
558         MONO_ADD_INS (bblock, cmp); \
559                 MONO_ADD_INS (bblock, ins);     \
560         } while (0)
561
562 /* *
563  * link_bblock: Links two basic blocks
564  *
565  * links two basic blocks in the control flow graph, the 'from'
566  * argument is the starting block and the 'to' argument is the block
567  * the control flow ends to after 'from'.
568  */
569 static void
570 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
571 {
572         MonoBasicBlock **newa;
573         int i, found;
574
575 #if 0
576         if (from->cil_code) {
577                 if (to->cil_code)
578                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
579                 else
580                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
581         } else {
582                 if (to->cil_code)
583                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
584                 else
585                         printf ("edge from entry to exit\n");
586         }
587 #endif
588
589         found = FALSE;
590         for (i = 0; i < from->out_count; ++i) {
591                 if (to == from->out_bb [i]) {
592                         found = TRUE;
593                         break;
594                 }
595         }
596         if (!found) {
597                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
598                 for (i = 0; i < from->out_count; ++i) {
599                         newa [i] = from->out_bb [i];
600                 }
601                 newa [i] = to;
602                 from->out_count++;
603                 from->out_bb = newa;
604         }
605
606         found = FALSE;
607         for (i = 0; i < to->in_count; ++i) {
608                 if (from == to->in_bb [i]) {
609                         found = TRUE;
610                         break;
611                 }
612         }
613         if (!found) {
614                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
615                 for (i = 0; i < to->in_count; ++i) {
616                         newa [i] = to->in_bb [i];
617                 }
618                 newa [i] = from;
619                 to->in_count++;
620                 to->in_bb = newa;
621         }
622 }
623
624 void
625 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
626 {
627         link_bblock (cfg, from, to);
628 }
629
630 /**
631  * mono_find_block_region:
632  *
633  *   We mark each basic block with a region ID. We use that to avoid BB
634  *   optimizations when blocks are in different regions.
635  *
636  * Returns:
637  *   A region token that encodes where this region is, and information
638  *   about the clause owner for this block.
639  *
640  *   The region encodes the try/catch/filter clause that owns this block
641  *   as well as the type.  -1 is a special value that represents a block
642  *   that is in none of try/catch/filter.
643  */
644 static int
645 mono_find_block_region (MonoCompile *cfg, int offset)
646 {
647         MonoMethodHeader *header = cfg->header;
648         MonoExceptionClause *clause;
649         int i;
650
651         for (i = 0; i < header->num_clauses; ++i) {
652                 clause = &header->clauses [i];
653                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
654                     (offset < (clause->handler_offset)))
655                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
656                            
657                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
658                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
659                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
660                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
661                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
662                         else
663                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
664                 }
665
666                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
667                         return ((i + 1) << 8) | clause->flags;
668         }
669
670         return -1;
671 }
672
673 static GList*
674 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
675 {
676         MonoMethodHeader *header = cfg->header;
677         MonoExceptionClause *clause;
678         int i;
679         GList *res = NULL;
680
681         for (i = 0; i < header->num_clauses; ++i) {
682                 clause = &header->clauses [i];
683                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
684                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
685                         if (clause->flags == type)
686                                 res = g_list_append (res, clause);
687                 }
688         }
689         return res;
690 }
691
692 static void
693 mono_create_spvar_for_region (MonoCompile *cfg, int region)
694 {
695         MonoInst *var;
696
697         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
698         if (var)
699                 return;
700
701         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
702         /* prevent it from being register allocated */
703         var->flags |= MONO_INST_VOLATILE;
704
705         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
706 }
707
708 MonoInst *
709 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
710 {
711         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
712 }
713
714 static MonoInst*
715 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
716 {
717         MonoInst *var;
718
719         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
720         if (var)
721                 return var;
722
723         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
724         /* prevent it from being register allocated */
725         var->flags |= MONO_INST_VOLATILE;
726
727         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
728
729         return var;
730 }
731
732 /*
733  * Returns the type used in the eval stack when @type is loaded.
734  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
735  */
736 void
737 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
738 {
739         MonoClass *klass;
740
741         type = mini_get_underlying_type (cfg, type);
742         inst->klass = klass = mono_class_from_mono_type (type);
743         if (type->byref) {
744                 inst->type = STACK_MP;
745                 return;
746         }
747
748 handle_enum:
749         switch (type->type) {
750         case MONO_TYPE_VOID:
751                 inst->type = STACK_INV;
752                 return;
753         case MONO_TYPE_I1:
754         case MONO_TYPE_U1:
755         case MONO_TYPE_BOOLEAN:
756         case MONO_TYPE_I2:
757         case MONO_TYPE_U2:
758         case MONO_TYPE_CHAR:
759         case MONO_TYPE_I4:
760         case MONO_TYPE_U4:
761                 inst->type = STACK_I4;
762                 return;
763         case MONO_TYPE_I:
764         case MONO_TYPE_U:
765         case MONO_TYPE_PTR:
766         case MONO_TYPE_FNPTR:
767                 inst->type = STACK_PTR;
768                 return;
769         case MONO_TYPE_CLASS:
770         case MONO_TYPE_STRING:
771         case MONO_TYPE_OBJECT:
772         case MONO_TYPE_SZARRAY:
773         case MONO_TYPE_ARRAY:    
774                 inst->type = STACK_OBJ;
775                 return;
776         case MONO_TYPE_I8:
777         case MONO_TYPE_U8:
778                 inst->type = STACK_I8;
779                 return;
780         case MONO_TYPE_R4:
781                 inst->type = cfg->r4_stack_type;
782                 break;
783         case MONO_TYPE_R8:
784                 inst->type = STACK_R8;
785                 return;
786         case MONO_TYPE_VALUETYPE:
787                 if (type->data.klass->enumtype) {
788                         type = mono_class_enum_basetype (type->data.klass);
789                         goto handle_enum;
790                 } else {
791                         inst->klass = klass;
792                         inst->type = STACK_VTYPE;
793                         return;
794                 }
795         case MONO_TYPE_TYPEDBYREF:
796                 inst->klass = mono_defaults.typed_reference_class;
797                 inst->type = STACK_VTYPE;
798                 return;
799         case MONO_TYPE_GENERICINST:
800                 type = &type->data.generic_class->container_class->byval_arg;
801                 goto handle_enum;
802         case MONO_TYPE_VAR:
803         case MONO_TYPE_MVAR:
804                 g_assert (cfg->generic_sharing_context);
805                 if (mini_is_gsharedvt_type (cfg, type)) {
806                         g_assert (cfg->gsharedvt);
807                         inst->type = STACK_VTYPE;
808                 } else {
809                         type_to_eval_stack_type (cfg, mini_get_underlying_type (cfg, type), inst);
810                 }
811                 return;
812         default:
813                 g_error ("unknown type 0x%02x in eval stack type", type->type);
814         }
815 }
816
817 /*
818  * The following tables are used to quickly validate the IL code in type_from_op ().
819  */
820 static const char
821 bin_num_table [STACK_MAX] [STACK_MAX] = {
822         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
823         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
824         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
825         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
826         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
827         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
828         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
831 };
832
833 static const char 
834 neg_table [] = {
835         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
836 };
837
838 /* reduce the size of this table */
839 static const char
840 bin_int_table [STACK_MAX] [STACK_MAX] = {
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
842         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
843         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
844         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
845         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
846         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
847         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
848         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
849 };
850
851 static const char
852 bin_comp_table [STACK_MAX] [STACK_MAX] = {
853 /*      Inv i  L  p  F  &  O  vt r4 */
854         {0},
855         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
856         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
857         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
858         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
859         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
860         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
861         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
862         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
863 };
864
865 /* reduce the size of this table */
866 static const char
867 shift_table [STACK_MAX] [STACK_MAX] = {
868         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
869         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
870         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
871         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
872         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
873         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
874         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
875         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
876 };
877
878 /*
879  * Tables to map from the non-specific opcode to the matching
880  * type-specific opcode.
881  */
882 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
883 static const guint16
884 binops_op_map [STACK_MAX] = {
885         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
886 };
887
888 /* handles from CEE_NEG to CEE_CONV_U8 */
889 static const guint16
890 unops_op_map [STACK_MAX] = {
891         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
892 };
893
894 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
895 static const guint16
896 ovfops_op_map [STACK_MAX] = {
897         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
898 };
899
900 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
901 static const guint16
902 ovf2ops_op_map [STACK_MAX] = {
903         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
904 };
905
906 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
907 static const guint16
908 ovf3ops_op_map [STACK_MAX] = {
909         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
910 };
911
912 /* handles from CEE_BEQ to CEE_BLT_UN */
913 static const guint16
914 beqops_op_map [STACK_MAX] = {
915         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
916 };
917
918 /* handles from CEE_CEQ to CEE_CLT_UN */
919 static const guint16
920 ceqops_op_map [STACK_MAX] = {
921         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
922 };
923
924 /*
925  * Sets ins->type (the type on the eval stack) according to the
926  * type of the opcode and the arguments to it.
927  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
928  *
929  * FIXME: this function sets ins->type unconditionally in some cases, but
930  * it should set it to invalid for some types (a conv.x on an object)
931  */
932 static void
933 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
934 {
935         switch (ins->opcode) {
936         /* binops */
937         case CEE_ADD:
938         case CEE_SUB:
939         case CEE_MUL:
940         case CEE_DIV:
941         case CEE_REM:
942                 /* FIXME: check unverifiable args for STACK_MP */
943                 ins->type = bin_num_table [src1->type] [src2->type];
944                 ins->opcode += binops_op_map [ins->type];
945                 break;
946         case CEE_DIV_UN:
947         case CEE_REM_UN:
948         case CEE_AND:
949         case CEE_OR:
950         case CEE_XOR:
951                 ins->type = bin_int_table [src1->type] [src2->type];
952                 ins->opcode += binops_op_map [ins->type];
953                 break;
954         case CEE_SHL:
955         case CEE_SHR:
956         case CEE_SHR_UN:
957                 ins->type = shift_table [src1->type] [src2->type];
958                 ins->opcode += binops_op_map [ins->type];
959                 break;
960         case OP_COMPARE:
961         case OP_LCOMPARE:
962         case OP_ICOMPARE:
963                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE;
966                 else if (src1->type == STACK_R4)
967                         ins->opcode = OP_RCOMPARE;
968                 else if (src1->type == STACK_R8)
969                         ins->opcode = OP_FCOMPARE;
970                 else
971                         ins->opcode = OP_ICOMPARE;
972                 break;
973         case OP_ICOMPARE_IMM:
974                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
975                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
976                         ins->opcode = OP_LCOMPARE_IMM;          
977                 break;
978         case CEE_BEQ:
979         case CEE_BGE:
980         case CEE_BGT:
981         case CEE_BLE:
982         case CEE_BLT:
983         case CEE_BNE_UN:
984         case CEE_BGE_UN:
985         case CEE_BGT_UN:
986         case CEE_BLE_UN:
987         case CEE_BLT_UN:
988                 ins->opcode += beqops_op_map [src1->type];
989                 break;
990         case OP_CEQ:
991                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
992                 ins->opcode += ceqops_op_map [src1->type];
993                 break;
994         case OP_CGT:
995         case OP_CGT_UN:
996         case OP_CLT:
997         case OP_CLT_UN:
998                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
999                 ins->opcode += ceqops_op_map [src1->type];
1000                 break;
1001         /* unops */
1002         case CEE_NEG:
1003                 ins->type = neg_table [src1->type];
1004                 ins->opcode += unops_op_map [ins->type];
1005                 break;
1006         case CEE_NOT:
1007                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
1008                         ins->type = src1->type;
1009                 else
1010                         ins->type = STACK_INV;
1011                 ins->opcode += unops_op_map [ins->type];
1012                 break;
1013         case CEE_CONV_I1:
1014         case CEE_CONV_I2:
1015         case CEE_CONV_I4:
1016         case CEE_CONV_U4:
1017                 ins->type = STACK_I4;
1018                 ins->opcode += unops_op_map [src1->type];
1019                 break;
1020         case CEE_CONV_R_UN:
1021                 ins->type = STACK_R8;
1022                 switch (src1->type) {
1023                 case STACK_I4:
1024                 case STACK_PTR:
1025                         ins->opcode = OP_ICONV_TO_R_UN;
1026                         break;
1027                 case STACK_I8:
1028                         ins->opcode = OP_LCONV_TO_R_UN; 
1029                         break;
1030                 }
1031                 break;
1032         case CEE_CONV_OVF_I1:
1033         case CEE_CONV_OVF_U1:
1034         case CEE_CONV_OVF_I2:
1035         case CEE_CONV_OVF_U2:
1036         case CEE_CONV_OVF_I4:
1037         case CEE_CONV_OVF_U4:
1038                 ins->type = STACK_I4;
1039                 ins->opcode += ovf3ops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I_UN:
1042         case CEE_CONV_OVF_U_UN:
1043                 ins->type = STACK_PTR;
1044                 ins->opcode += ovf2ops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_I1_UN:
1047         case CEE_CONV_OVF_I2_UN:
1048         case CEE_CONV_OVF_I4_UN:
1049         case CEE_CONV_OVF_U1_UN:
1050         case CEE_CONV_OVF_U2_UN:
1051         case CEE_CONV_OVF_U4_UN:
1052                 ins->type = STACK_I4;
1053                 ins->opcode += ovf2ops_op_map [src1->type];
1054                 break;
1055         case CEE_CONV_U:
1056                 ins->type = STACK_PTR;
1057                 switch (src1->type) {
1058                 case STACK_I4:
1059                         ins->opcode = OP_ICONV_TO_U;
1060                         break;
1061                 case STACK_PTR:
1062                 case STACK_MP:
1063 #if SIZEOF_VOID_P == 8
1064                         ins->opcode = OP_LCONV_TO_U;
1065 #else
1066                         ins->opcode = OP_MOVE;
1067 #endif
1068                         break;
1069                 case STACK_I8:
1070                         ins->opcode = OP_LCONV_TO_U;
1071                         break;
1072                 case STACK_R8:
1073                         ins->opcode = OP_FCONV_TO_U;
1074                         break;
1075                 }
1076                 break;
1077         case CEE_CONV_I8:
1078         case CEE_CONV_U8:
1079                 ins->type = STACK_I8;
1080                 ins->opcode += unops_op_map [src1->type];
1081                 break;
1082         case CEE_CONV_OVF_I8:
1083         case CEE_CONV_OVF_U8:
1084                 ins->type = STACK_I8;
1085                 ins->opcode += ovf3ops_op_map [src1->type];
1086                 break;
1087         case CEE_CONV_OVF_U8_UN:
1088         case CEE_CONV_OVF_I8_UN:
1089                 ins->type = STACK_I8;
1090                 ins->opcode += ovf2ops_op_map [src1->type];
1091                 break;
1092         case CEE_CONV_R4:
1093                 ins->type = cfg->r4_stack_type;
1094                 ins->opcode += unops_op_map [src1->type];
1095                 break;
1096         case CEE_CONV_R8:
1097                 ins->type = STACK_R8;
1098                 ins->opcode += unops_op_map [src1->type];
1099                 break;
1100         case OP_CKFINITE:
1101                 ins->type = STACK_R8;           
1102                 break;
1103         case CEE_CONV_U2:
1104         case CEE_CONV_U1:
1105                 ins->type = STACK_I4;
1106                 ins->opcode += ovfops_op_map [src1->type];
1107                 break;
1108         case CEE_CONV_I:
1109         case CEE_CONV_OVF_I:
1110         case CEE_CONV_OVF_U:
1111                 ins->type = STACK_PTR;
1112                 ins->opcode += ovfops_op_map [src1->type];
1113                 break;
1114         case CEE_ADD_OVF:
1115         case CEE_ADD_OVF_UN:
1116         case CEE_MUL_OVF:
1117         case CEE_MUL_OVF_UN:
1118         case CEE_SUB_OVF:
1119         case CEE_SUB_OVF_UN:
1120                 ins->type = bin_num_table [src1->type] [src2->type];
1121                 ins->opcode += ovfops_op_map [src1->type];
1122                 if (ins->type == STACK_R8)
1123                         ins->type = STACK_INV;
1124                 break;
1125         case OP_LOAD_MEMBASE:
1126                 ins->type = STACK_PTR;
1127                 break;
1128         case OP_LOADI1_MEMBASE:
1129         case OP_LOADU1_MEMBASE:
1130         case OP_LOADI2_MEMBASE:
1131         case OP_LOADU2_MEMBASE:
1132         case OP_LOADI4_MEMBASE:
1133         case OP_LOADU4_MEMBASE:
1134                 ins->type = STACK_PTR;
1135                 break;
1136         case OP_LOADI8_MEMBASE:
1137                 ins->type = STACK_I8;
1138                 break;
1139         case OP_LOADR4_MEMBASE:
1140                 ins->type = cfg->r4_stack_type;
1141                 break;
1142         case OP_LOADR8_MEMBASE:
1143                 ins->type = STACK_R8;
1144                 break;
1145         default:
1146                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1147                 break;
1148         }
1149
1150         if (ins->type == STACK_MP)
1151                 ins->klass = mono_defaults.object_class;
1152 }
1153
1154 static const char 
1155 ldind_type [] = {
1156         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1157 };
1158
1159 #if 0
1160
1161 static const char
1162 param_table [STACK_MAX] [STACK_MAX] = {
1163         {0},
1164 };
1165
1166 static int
1167 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1168         int i;
1169
1170         if (sig->hasthis) {
1171                 switch (args->type) {
1172                 case STACK_I4:
1173                 case STACK_I8:
1174                 case STACK_R8:
1175                 case STACK_VTYPE:
1176                 case STACK_INV:
1177                         return 0;
1178                 }
1179                 args++;
1180         }
1181         for (i = 0; i < sig->param_count; ++i) {
1182                 switch (args [i].type) {
1183                 case STACK_INV:
1184                         return 0;
1185                 case STACK_MP:
1186                         if (!sig->params [i]->byref)
1187                                 return 0;
1188                         continue;
1189                 case STACK_OBJ:
1190                         if (sig->params [i]->byref)
1191                                 return 0;
1192                         switch (sig->params [i]->type) {
1193                         case MONO_TYPE_CLASS:
1194                         case MONO_TYPE_STRING:
1195                         case MONO_TYPE_OBJECT:
1196                         case MONO_TYPE_SZARRAY:
1197                         case MONO_TYPE_ARRAY:
1198                                 break;
1199                         default:
1200                                 return 0;
1201                         }
1202                         continue;
1203                 case STACK_R8:
1204                         if (sig->params [i]->byref)
1205                                 return 0;
1206                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1207                                 return 0;
1208                         continue;
1209                 case STACK_PTR:
1210                 case STACK_I4:
1211                 case STACK_I8:
1212                 case STACK_VTYPE:
1213                         break;
1214                 }
1215                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1216                         return 0;*/
1217         }
1218         return 1;
1219 }
1220 #endif
1221
1222 /*
1223  * When we need a pointer to the current domain many times in a method, we
1224  * call mono_domain_get() once and we store the result in a local variable.
1225  * This function returns the variable that represents the MonoDomain*.
1226  */
1227 inline static MonoInst *
1228 mono_get_domainvar (MonoCompile *cfg)
1229 {
1230         if (!cfg->domainvar)
1231                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1232         return cfg->domainvar;
1233 }
1234
1235 /*
1236  * The got_var contains the address of the Global Offset Table when AOT 
1237  * compiling.
1238  */
1239 MonoInst *
1240 mono_get_got_var (MonoCompile *cfg)
1241 {
1242 #ifdef MONO_ARCH_NEED_GOT_VAR
1243         if (!cfg->compile_aot)
1244                 return NULL;
1245         if (!cfg->got_var) {
1246                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247         }
1248         return cfg->got_var;
1249 #else
1250         return NULL;
1251 #endif
1252 }
1253
1254 static MonoInst *
1255 mono_get_vtable_var (MonoCompile *cfg)
1256 {
1257         g_assert (cfg->generic_sharing_context);
1258
1259         if (!cfg->rgctx_var) {
1260                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1261                 /* force the var to be stack allocated */
1262                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1263         }
1264
1265         return cfg->rgctx_var;
1266 }
1267
1268 static MonoType*
1269 type_from_stack_type (MonoInst *ins) {
1270         switch (ins->type) {
1271         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1272         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1273         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1274         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1275         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1276         case STACK_MP:
1277                 return &ins->klass->this_arg;
1278         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1279         case STACK_VTYPE: return &ins->klass->byval_arg;
1280         default:
1281                 g_error ("stack type %d to monotype not handled\n", ins->type);
1282         }
1283         return NULL;
1284 }
1285
1286 static G_GNUC_UNUSED int
1287 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1288 {
1289         t = mono_type_get_underlying_type (t);
1290         switch (t->type) {
1291         case MONO_TYPE_I1:
1292         case MONO_TYPE_U1:
1293         case MONO_TYPE_BOOLEAN:
1294         case MONO_TYPE_I2:
1295         case MONO_TYPE_U2:
1296         case MONO_TYPE_CHAR:
1297         case MONO_TYPE_I4:
1298         case MONO_TYPE_U4:
1299                 return STACK_I4;
1300         case MONO_TYPE_I:
1301         case MONO_TYPE_U:
1302         case MONO_TYPE_PTR:
1303         case MONO_TYPE_FNPTR:
1304                 return STACK_PTR;
1305         case MONO_TYPE_CLASS:
1306         case MONO_TYPE_STRING:
1307         case MONO_TYPE_OBJECT:
1308         case MONO_TYPE_SZARRAY:
1309         case MONO_TYPE_ARRAY:    
1310                 return STACK_OBJ;
1311         case MONO_TYPE_I8:
1312         case MONO_TYPE_U8:
1313                 return STACK_I8;
1314         case MONO_TYPE_R4:
1315                 return cfg->r4_stack_type;
1316         case MONO_TYPE_R8:
1317                 return STACK_R8;
1318         case MONO_TYPE_VALUETYPE:
1319         case MONO_TYPE_TYPEDBYREF:
1320                 return STACK_VTYPE;
1321         case MONO_TYPE_GENERICINST:
1322                 if (mono_type_generic_inst_is_valuetype (t))
1323                         return STACK_VTYPE;
1324                 else
1325                         return STACK_OBJ;
1326                 break;
1327         default:
1328                 g_assert_not_reached ();
1329         }
1330
1331         return -1;
1332 }
1333
1334 static MonoClass*
1335 array_access_to_klass (int opcode)
1336 {
1337         switch (opcode) {
1338         case CEE_LDELEM_U1:
1339                 return mono_defaults.byte_class;
1340         case CEE_LDELEM_U2:
1341                 return mono_defaults.uint16_class;
1342         case CEE_LDELEM_I:
1343         case CEE_STELEM_I:
1344                 return mono_defaults.int_class;
1345         case CEE_LDELEM_I1:
1346         case CEE_STELEM_I1:
1347                 return mono_defaults.sbyte_class;
1348         case CEE_LDELEM_I2:
1349         case CEE_STELEM_I2:
1350                 return mono_defaults.int16_class;
1351         case CEE_LDELEM_I4:
1352         case CEE_STELEM_I4:
1353                 return mono_defaults.int32_class;
1354         case CEE_LDELEM_U4:
1355                 return mono_defaults.uint32_class;
1356         case CEE_LDELEM_I8:
1357         case CEE_STELEM_I8:
1358                 return mono_defaults.int64_class;
1359         case CEE_LDELEM_R4:
1360         case CEE_STELEM_R4:
1361                 return mono_defaults.single_class;
1362         case CEE_LDELEM_R8:
1363         case CEE_STELEM_R8:
1364                 return mono_defaults.double_class;
1365         case CEE_LDELEM_REF:
1366         case CEE_STELEM_REF:
1367                 return mono_defaults.object_class;
1368         default:
1369                 g_assert_not_reached ();
1370         }
1371         return NULL;
1372 }
1373
1374 /*
1375  * We try to share variables when possible
1376  */
1377 static MonoInst *
1378 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1379 {
1380         MonoInst *res;
1381         int pos, vnum;
1382
1383         /* inlining can result in deeper stacks */ 
1384         if (slot >= cfg->header->max_stack)
1385                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1386
1387         pos = ins->type - 1 + slot * STACK_MAX;
1388
1389         switch (ins->type) {
1390         case STACK_I4:
1391         case STACK_I8:
1392         case STACK_R8:
1393         case STACK_PTR:
1394         case STACK_MP:
1395         case STACK_OBJ:
1396                 if ((vnum = cfg->intvars [pos]))
1397                         return cfg->varinfo [vnum];
1398                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1399                 cfg->intvars [pos] = res->inst_c0;
1400                 break;
1401         default:
1402                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1403         }
1404         return res;
1405 }
1406
1407 static void
1408 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1409 {
1410         /* 
1411          * Don't use this if a generic_context is set, since that means AOT can't
1412          * look up the method using just the image+token.
1413          * table == 0 means this is a reference made from a wrapper.
1414          */
1415         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1416                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1417                 jump_info_token->image = image;
1418                 jump_info_token->token = token;
1419                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1420         }
1421 }
1422
1423 /*
1424  * This function is called to handle items that are left on the evaluation stack
1425  * at basic block boundaries. What happens is that we save the values to local variables
1426  * and we reload them later when first entering the target basic block (with the
1427  * handle_loaded_temps () function).
1428  * A single joint point will use the same variables (stored in the array bb->out_stack or
1429  * bb->in_stack, if the basic block is before or after the joint point).
1430  *
1431  * This function needs to be called _before_ emitting the last instruction of
1432  * the bb (i.e. before emitting a branch).
1433  * If the stack merge fails at a join point, cfg->unverifiable is set.
1434  */
1435 static void
1436 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1437 {
1438         int i, bindex;
1439         MonoBasicBlock *bb = cfg->cbb;
1440         MonoBasicBlock *outb;
1441         MonoInst *inst, **locals;
1442         gboolean found;
1443
1444         if (!count)
1445                 return;
1446         if (cfg->verbose_level > 3)
1447                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1448         if (!bb->out_scount) {
1449                 bb->out_scount = count;
1450                 //printf ("bblock %d has out:", bb->block_num);
1451                 found = FALSE;
1452                 for (i = 0; i < bb->out_count; ++i) {
1453                         outb = bb->out_bb [i];
1454                         /* exception handlers are linked, but they should not be considered for stack args */
1455                         if (outb->flags & BB_EXCEPTION_HANDLER)
1456                                 continue;
1457                         //printf (" %d", outb->block_num);
1458                         if (outb->in_stack) {
1459                                 found = TRUE;
1460                                 bb->out_stack = outb->in_stack;
1461                                 break;
1462                         }
1463                 }
1464                 //printf ("\n");
1465                 if (!found) {
1466                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1467                         for (i = 0; i < count; ++i) {
1468                                 /* 
1469                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1470                                  * stack slot and if they are of the same type.
1471                                  * This won't cause conflicts since if 'local' is used to 
1472                                  * store one of the values in the in_stack of a bblock, then
1473                                  * the same variable will be used for the same outgoing stack 
1474                                  * slot as well. 
1475                                  * This doesn't work when inlining methods, since the bblocks
1476                                  * in the inlined methods do not inherit their in_stack from
1477                                  * the bblock they are inlined to. See bug #58863 for an
1478                                  * example.
1479                                  */
1480                                 if (cfg->inlined_method)
1481                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1482                                 else
1483                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1484                         }
1485                 }
1486         }
1487
1488         for (i = 0; i < bb->out_count; ++i) {
1489                 outb = bb->out_bb [i];
1490                 /* exception handlers are linked, but they should not be considered for stack args */
1491                 if (outb->flags & BB_EXCEPTION_HANDLER)
1492                         continue;
1493                 if (outb->in_scount) {
1494                         if (outb->in_scount != bb->out_scount) {
1495                                 cfg->unverifiable = TRUE;
1496                                 return;
1497                         }
1498                         continue; /* check they are the same locals */
1499                 }
1500                 outb->in_scount = count;
1501                 outb->in_stack = bb->out_stack;
1502         }
1503
1504         locals = bb->out_stack;
1505         cfg->cbb = bb;
1506         for (i = 0; i < count; ++i) {
1507                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1508                 inst->cil_code = sp [i]->cil_code;
1509                 sp [i] = locals [i];
1510                 if (cfg->verbose_level > 3)
1511                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1512         }
1513
1514         /*
1515          * It is possible that the out bblocks already have in_stack assigned, and
1516          * the in_stacks differ. In this case, we will store to all the different 
1517          * in_stacks.
1518          */
1519
1520         found = TRUE;
1521         bindex = 0;
1522         while (found) {
1523                 /* Find a bblock which has a different in_stack */
1524                 found = FALSE;
1525                 while (bindex < bb->out_count) {
1526                         outb = bb->out_bb [bindex];
1527                         /* exception handlers are linked, but they should not be considered for stack args */
1528                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1529                                 bindex++;
1530                                 continue;
1531                         }
1532                         if (outb->in_stack != locals) {
1533                                 for (i = 0; i < count; ++i) {
1534                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1535                                         inst->cil_code = sp [i]->cil_code;
1536                                         sp [i] = locals [i];
1537                                         if (cfg->verbose_level > 3)
1538                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1539                                 }
1540                                 locals = outb->in_stack;
1541                                 found = TRUE;
1542                                 break;
1543                         }
1544                         bindex ++;
1545                 }
1546         }
1547 }
1548
1549 /* Emit code which loads interface_offsets [klass->interface_id]
1550  * The array is stored in memory before vtable.
1551 */
1552 static void
1553 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1554 {
1555         if (cfg->compile_aot) {
1556                 int ioffset_reg = alloc_preg (cfg);
1557                 int iid_reg = alloc_preg (cfg);
1558
1559                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1560                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1562         }
1563         else {
1564                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1565         }
1566 }
1567
1568 static void
1569 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1570 {
1571         int ibitmap_reg = alloc_preg (cfg);
1572 #ifdef COMPRESSED_INTERFACE_BITMAP
1573         MonoInst *args [2];
1574         MonoInst *res, *ins;
1575         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1576         MONO_ADD_INS (cfg->cbb, ins);
1577         args [0] = ins;
1578         if (cfg->compile_aot)
1579                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1580         else
1581                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1582         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1583         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1584 #else
1585         int ibitmap_byte_reg = alloc_preg (cfg);
1586
1587         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1588
1589         if (cfg->compile_aot) {
1590                 int iid_reg = alloc_preg (cfg);
1591                 int shifted_iid_reg = alloc_preg (cfg);
1592                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1593                 int masked_iid_reg = alloc_preg (cfg);
1594                 int iid_one_bit_reg = alloc_preg (cfg);
1595                 int iid_bit_reg = alloc_preg (cfg);
1596                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1598                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1599                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1600                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1601                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1602                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1603                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1604         } else {
1605                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1606                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1607         }
1608 #endif
1609 }
1610
1611 /* 
1612  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1613  * stored in "klass_reg" implements the interface "klass".
1614  */
1615 static void
1616 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1617 {
1618         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1619 }
1620
1621 /* 
1622  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1623  * stored in "vtable_reg" implements the interface "klass".
1624  */
1625 static void
1626 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1627 {
1628         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1629 }
1630
1631 /* 
1632  * Emit code which checks whenever the interface id of @klass is smaller than
1633  * than the value given by max_iid_reg.
1634 */
1635 static void
1636 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1637                                                  MonoBasicBlock *false_target)
1638 {
1639         if (cfg->compile_aot) {
1640                 int iid_reg = alloc_preg (cfg);
1641                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1642                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1643         }
1644         else
1645                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1646         if (false_target)
1647                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1648         else
1649                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1650 }
1651
1652 /* Same as above, but obtains max_iid from a vtable */
1653 static void
1654 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1655                                                                  MonoBasicBlock *false_target)
1656 {
1657         int max_iid_reg = alloc_preg (cfg);
1658                 
1659         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1660         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1661 }
1662
1663 /* Same as above, but obtains max_iid from a klass */
1664 static void
1665 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1666                                                                  MonoBasicBlock *false_target)
1667 {
1668         int max_iid_reg = alloc_preg (cfg);
1669
1670         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1671         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1672 }
1673
1674 static void
1675 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1676 {
1677         int idepth_reg = alloc_preg (cfg);
1678         int stypes_reg = alloc_preg (cfg);
1679         int stype = alloc_preg (cfg);
1680
1681         mono_class_setup_supertypes (klass);
1682
1683         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1684                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1685                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1686                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1687         }
1688         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1689         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1690         if (klass_ins) {
1691                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1692         } else if (cfg->compile_aot) {
1693                 int const_reg = alloc_preg (cfg);
1694                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1695                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1696         } else {
1697                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1698         }
1699         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1700 }
1701
1702 static void
1703 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1704 {
1705         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1706 }
1707
1708 static void
1709 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1710 {
1711         int intf_reg = alloc_preg (cfg);
1712
1713         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1714         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1715         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1716         if (true_target)
1717                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1718         else
1719                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1720 }
1721
1722 /*
1723  * Variant of the above that takes a register to the class, not the vtable.
1724  */
1725 static void
1726 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1727 {
1728         int intf_bit_reg = alloc_preg (cfg);
1729
1730         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1731         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1732         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1733         if (true_target)
1734                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1735         else
1736                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1737 }
1738
1739 static inline void
1740 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1741 {
1742         if (klass_inst) {
1743                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1744         } else if (cfg->compile_aot) {
1745                 int const_reg = alloc_preg (cfg);
1746                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1747                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1748         } else {
1749                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1750         }
1751         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1752 }
1753
1754 static inline void
1755 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1756 {
1757         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1758 }
1759
1760 static inline void
1761 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1762 {
1763         if (cfg->compile_aot) {
1764                 int const_reg = alloc_preg (cfg);
1765                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1766                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1767         } else {
1768                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1769         }
1770         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1771 }
1772
1773 static void
1774 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1775         
1776 static void
1777 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1778 {
1779         if (klass->rank) {
1780                 int rank_reg = alloc_preg (cfg);
1781                 int eclass_reg = alloc_preg (cfg);
1782
1783                 g_assert (!klass_inst);
1784                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1785                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1786                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1787                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1788                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1789                 if (klass->cast_class == mono_defaults.object_class) {
1790                         int parent_reg = alloc_preg (cfg);
1791                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1792                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1793                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1794                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1795                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1796                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1797                 } else if (klass->cast_class == mono_defaults.enum_class) {
1798                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1799                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1800                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1801                 } else {
1802                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1803                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1804                 }
1805
1806                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1807                         /* Check that the object is a vector too */
1808                         int bounds_reg = alloc_preg (cfg);
1809                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1810                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1811                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1812                 }
1813         } else {
1814                 int idepth_reg = alloc_preg (cfg);
1815                 int stypes_reg = alloc_preg (cfg);
1816                 int stype = alloc_preg (cfg);
1817
1818                 mono_class_setup_supertypes (klass);
1819
1820                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1821                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1822                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1823                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1824                 }
1825                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1826                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1827                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1828         }
1829 }
1830
1831 static void
1832 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1833 {
1834         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1835 }
1836
1837 static void 
1838 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1839 {
1840         int val_reg;
1841
1842         g_assert (val == 0);
1843
1844         if (align == 0)
1845                 align = 4;
1846
1847         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1848                 switch (size) {
1849                 case 1:
1850                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1851                         return;
1852                 case 2:
1853                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1854                         return;
1855                 case 4:
1856                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1857                         return;
1858 #if SIZEOF_REGISTER == 8
1859                 case 8:
1860                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1861                         return;
1862 #endif
1863                 }
1864         }
1865
1866         val_reg = alloc_preg (cfg);
1867
1868         if (SIZEOF_REGISTER == 8)
1869                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1870         else
1871                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1872
1873         if (align < 4) {
1874                 /* This could be optimized further if neccesary */
1875                 while (size >= 1) {
1876                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1877                         offset += 1;
1878                         size -= 1;
1879                 }
1880                 return;
1881         }       
1882
1883 #if !NO_UNALIGNED_ACCESS
1884         if (SIZEOF_REGISTER == 8) {
1885                 if (offset % 8) {
1886                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1887                         offset += 4;
1888                         size -= 4;
1889                 }
1890                 while (size >= 8) {
1891                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1892                         offset += 8;
1893                         size -= 8;
1894                 }
1895         }       
1896 #endif
1897
1898         while (size >= 4) {
1899                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1900                 offset += 4;
1901                 size -= 4;
1902         }
1903         while (size >= 2) {
1904                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1905                 offset += 2;
1906                 size -= 2;
1907         }
1908         while (size >= 1) {
1909                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1910                 offset += 1;
1911                 size -= 1;
1912         }
1913 }
1914
1915 void 
1916 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1917 {
1918         int cur_reg;
1919
1920         if (align == 0)
1921                 align = 4;
1922
1923         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1924         g_assert (size < 10000);
1925
1926         if (align < 4) {
1927                 /* This could be optimized further if neccesary */
1928                 while (size >= 1) {
1929                         cur_reg = alloc_preg (cfg);
1930                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1931                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1932                         doffset += 1;
1933                         soffset += 1;
1934                         size -= 1;
1935                 }
1936         }
1937
1938 #if !NO_UNALIGNED_ACCESS
1939         if (SIZEOF_REGISTER == 8) {
1940                 while (size >= 8) {
1941                         cur_reg = alloc_preg (cfg);
1942                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1943                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1944                         doffset += 8;
1945                         soffset += 8;
1946                         size -= 8;
1947                 }
1948         }       
1949 #endif
1950
1951         while (size >= 4) {
1952                 cur_reg = alloc_preg (cfg);
1953                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1954                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1955                 doffset += 4;
1956                 soffset += 4;
1957                 size -= 4;
1958         }
1959         while (size >= 2) {
1960                 cur_reg = alloc_preg (cfg);
1961                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1962                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1963                 doffset += 2;
1964                 soffset += 2;
1965                 size -= 2;
1966         }
1967         while (size >= 1) {
1968                 cur_reg = alloc_preg (cfg);
1969                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1970                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1971                 doffset += 1;
1972                 soffset += 1;
1973                 size -= 1;
1974         }
1975 }
1976
1977 static void
1978 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1979 {
1980         MonoInst *ins, *c;
1981
1982         if (cfg->compile_aot) {
1983                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1984                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1985                 ins->sreg1 = sreg1;
1986                 ins->sreg2 = c->dreg;
1987                 MONO_ADD_INS (cfg->cbb, ins);
1988         } else {
1989                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1990                 ins->sreg1 = sreg1;
1991                 ins->inst_offset = mini_get_tls_offset (tls_key);
1992                 MONO_ADD_INS (cfg->cbb, ins);
1993         }
1994 }
1995
1996 /*
1997  * emit_push_lmf:
1998  *
1999  *   Emit IR to push the current LMF onto the LMF stack.
2000  */
2001 static void
2002 emit_push_lmf (MonoCompile *cfg)
2003 {
2004         /*
2005          * Emit IR to push the LMF:
2006          * lmf_addr = <lmf_addr from tls>
2007          * lmf->lmf_addr = lmf_addr
2008          * lmf->prev_lmf = *lmf_addr
2009          * *lmf_addr = lmf
2010          */
2011         int lmf_reg, prev_lmf_reg;
2012         MonoInst *ins, *lmf_ins;
2013
2014         if (!cfg->lmf_ir)
2015                 return;
2016
2017         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2018                 /* Load current lmf */
2019                 lmf_ins = mono_get_lmf_intrinsic (cfg);
2020                 g_assert (lmf_ins);
2021                 MONO_ADD_INS (cfg->cbb, lmf_ins);
2022                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2023                 lmf_reg = ins->dreg;
2024                 /* Save previous_lmf */
2025                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2026                 /* Set new LMF */
2027                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2028         } else {
2029                 /*
2030                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2031                  */
2032                 if (!cfg->lmf_addr_var)
2033                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2034
2035 #ifdef HOST_WIN32
2036                 ins = mono_get_jit_tls_intrinsic (cfg);
2037                 if (ins) {
2038                         int jit_tls_dreg = ins->dreg;
2039
2040                         MONO_ADD_INS (cfg->cbb, ins);
2041                         lmf_reg = alloc_preg (cfg);
2042                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2043                 } else {
2044                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2045                 }
2046 #else
2047                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2048                 if (lmf_ins) {
2049                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2050                 } else {
2051 #ifdef TARGET_IOS
2052                         MonoInst *args [16], *jit_tls_ins, *ins;
2053
2054                         /* Inline mono_get_lmf_addr () */
2055                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2056
2057                         /* Load mono_jit_tls_id */
2058                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2059                         /* call pthread_getspecific () */
2060                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2061                         /* lmf_addr = &jit_tls->lmf */
2062                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2063                         lmf_ins = ins;
2064 #else
2065                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2066 #endif
2067                 }
2068 #endif
2069                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2070
2071                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2072                 lmf_reg = ins->dreg;
2073
2074                 prev_lmf_reg = alloc_preg (cfg);
2075                 /* Save previous_lmf */
2076                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2077                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2078                 /* Set new lmf */
2079                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2080         }
2081 }
2082
2083 /*
2084  * emit_pop_lmf:
2085  *
2086  *   Emit IR to pop the current LMF from the LMF stack.
2087  */
2088 static void
2089 emit_pop_lmf (MonoCompile *cfg)
2090 {
2091         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2092         MonoInst *ins;
2093
2094         if (!cfg->lmf_ir)
2095                 return;
2096
2097         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2098         lmf_reg = ins->dreg;
2099
2100         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2101                 /* Load previous_lmf */
2102                 prev_lmf_reg = alloc_preg (cfg);
2103                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2104                 /* Set new LMF */
2105                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2106         } else {
2107                 /*
2108                  * Emit IR to pop the LMF:
2109                  * *(lmf->lmf_addr) = lmf->prev_lmf
2110                  */
2111                 /* This could be called before emit_push_lmf () */
2112                 if (!cfg->lmf_addr_var)
2113                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2114                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2115
2116                 prev_lmf_reg = alloc_preg (cfg);
2117                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2118                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2119         }
2120 }
2121
2122 static void
2123 emit_instrumentation_call (MonoCompile *cfg, void *func)
2124 {
2125         MonoInst *iargs [1];
2126
2127         /*
2128          * Avoid instrumenting inlined methods since it can
2129          * distort profiling results.
2130          */
2131         if (cfg->method != cfg->current_method)
2132                 return;
2133
2134         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2135                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2136                 mono_emit_jit_icall (cfg, func, iargs);
2137         }
2138 }
2139
2140 static int
2141 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2142 {
2143 handle_enum:
2144         type = mini_get_underlying_type (cfg, type);
2145         switch (type->type) {
2146         case MONO_TYPE_VOID:
2147                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2148         case MONO_TYPE_I1:
2149         case MONO_TYPE_U1:
2150         case MONO_TYPE_BOOLEAN:
2151         case MONO_TYPE_I2:
2152         case MONO_TYPE_U2:
2153         case MONO_TYPE_CHAR:
2154         case MONO_TYPE_I4:
2155         case MONO_TYPE_U4:
2156                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2157         case MONO_TYPE_I:
2158         case MONO_TYPE_U:
2159         case MONO_TYPE_PTR:
2160         case MONO_TYPE_FNPTR:
2161                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2162         case MONO_TYPE_CLASS:
2163         case MONO_TYPE_STRING:
2164         case MONO_TYPE_OBJECT:
2165         case MONO_TYPE_SZARRAY:
2166         case MONO_TYPE_ARRAY:    
2167                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2168         case MONO_TYPE_I8:
2169         case MONO_TYPE_U8:
2170                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2171         case MONO_TYPE_R4:
2172                 if (cfg->r4fp)
2173                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2174                 else
2175                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2176         case MONO_TYPE_R8:
2177                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2178         case MONO_TYPE_VALUETYPE:
2179                 if (type->data.klass->enumtype) {
2180                         type = mono_class_enum_basetype (type->data.klass);
2181                         goto handle_enum;
2182                 } else
2183                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2184         case MONO_TYPE_TYPEDBYREF:
2185                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2186         case MONO_TYPE_GENERICINST:
2187                 type = &type->data.generic_class->container_class->byval_arg;
2188                 goto handle_enum;
2189         case MONO_TYPE_VAR:
2190         case MONO_TYPE_MVAR:
2191                 /* gsharedvt */
2192                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2193         default:
2194                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2195         }
2196         return -1;
2197 }
2198
2199 /*
2200  * target_type_is_incompatible:
2201  * @cfg: MonoCompile context
2202  *
2203  * Check that the item @arg on the evaluation stack can be stored
2204  * in the target type (can be a local, or field, etc).
2205  * The cfg arg can be used to check if we need verification or just
2206  * validity checks.
2207  *
2208  * Returns: non-0 value if arg can't be stored on a target.
2209  */
2210 static int
2211 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2212 {
2213         MonoType *simple_type;
2214         MonoClass *klass;
2215
2216         if (target->byref) {
2217                 /* FIXME: check that the pointed to types match */
2218                 if (arg->type == STACK_MP)
2219                         return arg->klass != mono_class_from_mono_type (target);
2220                 if (arg->type == STACK_PTR)
2221                         return 0;
2222                 return 1;
2223         }
2224
2225         simple_type = mini_get_underlying_type (cfg, target);
2226         switch (simple_type->type) {
2227         case MONO_TYPE_VOID:
2228                 return 1;
2229         case MONO_TYPE_I1:
2230         case MONO_TYPE_U1:
2231         case MONO_TYPE_BOOLEAN:
2232         case MONO_TYPE_I2:
2233         case MONO_TYPE_U2:
2234         case MONO_TYPE_CHAR:
2235         case MONO_TYPE_I4:
2236         case MONO_TYPE_U4:
2237                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2238                         return 1;
2239                 return 0;
2240         case MONO_TYPE_PTR:
2241                 /* STACK_MP is needed when setting pinned locals */
2242                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2243                         return 1;
2244                 return 0;
2245         case MONO_TYPE_I:
2246         case MONO_TYPE_U:
2247         case MONO_TYPE_FNPTR:
2248                 /* 
2249                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2250                  * in native int. (#688008).
2251                  */
2252                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_CLASS:
2256         case MONO_TYPE_STRING:
2257         case MONO_TYPE_OBJECT:
2258         case MONO_TYPE_SZARRAY:
2259         case MONO_TYPE_ARRAY:    
2260                 if (arg->type != STACK_OBJ)
2261                         return 1;
2262                 /* FIXME: check type compatibility */
2263                 return 0;
2264         case MONO_TYPE_I8:
2265         case MONO_TYPE_U8:
2266                 if (arg->type != STACK_I8)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_R4:
2270                 if (arg->type != cfg->r4_stack_type)
2271                         return 1;
2272                 return 0;
2273         case MONO_TYPE_R8:
2274                 if (arg->type != STACK_R8)
2275                         return 1;
2276                 return 0;
2277         case MONO_TYPE_VALUETYPE:
2278                 if (arg->type != STACK_VTYPE)
2279                         return 1;
2280                 klass = mono_class_from_mono_type (simple_type);
2281                 if (klass != arg->klass)
2282                         return 1;
2283                 return 0;
2284         case MONO_TYPE_TYPEDBYREF:
2285                 if (arg->type != STACK_VTYPE)
2286                         return 1;
2287                 klass = mono_class_from_mono_type (simple_type);
2288                 if (klass != arg->klass)
2289                         return 1;
2290                 return 0;
2291         case MONO_TYPE_GENERICINST:
2292                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2293                         if (arg->type != STACK_VTYPE)
2294                                 return 1;
2295                         klass = mono_class_from_mono_type (simple_type);
2296                         if (klass != arg->klass)
2297                                 return 1;
2298                         return 0;
2299                 } else {
2300                         if (arg->type != STACK_OBJ)
2301                                 return 1;
2302                         /* FIXME: check type compatibility */
2303                         return 0;
2304                 }
2305         case MONO_TYPE_VAR:
2306         case MONO_TYPE_MVAR:
2307                 g_assert (cfg->generic_sharing_context);
2308                 if (mini_type_var_is_vt (cfg, simple_type)) {
2309                         if (arg->type != STACK_VTYPE)
2310                                 return 1;
2311                 } else {
2312                         if (arg->type != STACK_OBJ)
2313                                 return 1;
2314                 }
2315                 return 0;
2316         default:
2317                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2318         }
2319         return 1;
2320 }
2321
2322 /*
2323  * Prepare arguments for passing to a function call.
2324  * Return a non-zero value if the arguments can't be passed to the given
2325  * signature.
2326  * The type checks are not yet complete and some conversions may need
2327  * casts on 32 or 64 bit architectures.
2328  *
2329  * FIXME: implement this using target_type_is_incompatible ()
2330  */
2331 static int
2332 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2333 {
2334         MonoType *simple_type;
2335         int i;
2336
2337         if (sig->hasthis) {
2338                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2339                         return 1;
2340                 args++;
2341         }
2342         for (i = 0; i < sig->param_count; ++i) {
2343                 if (sig->params [i]->byref) {
2344                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2345                                 return 1;
2346                         continue;
2347                 }
2348                 simple_type = mini_get_underlying_type (cfg, sig->params [i]);
2349 handle_enum:
2350                 switch (simple_type->type) {
2351                 case MONO_TYPE_VOID:
2352                         return 1;
2353                         continue;
2354                 case MONO_TYPE_I1:
2355                 case MONO_TYPE_U1:
2356                 case MONO_TYPE_BOOLEAN:
2357                 case MONO_TYPE_I2:
2358                 case MONO_TYPE_U2:
2359                 case MONO_TYPE_CHAR:
2360                 case MONO_TYPE_I4:
2361                 case MONO_TYPE_U4:
2362                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2363                                 return 1;
2364                         continue;
2365                 case MONO_TYPE_I:
2366                 case MONO_TYPE_U:
2367                 case MONO_TYPE_PTR:
2368                 case MONO_TYPE_FNPTR:
2369                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_CLASS:
2373                 case MONO_TYPE_STRING:
2374                 case MONO_TYPE_OBJECT:
2375                 case MONO_TYPE_SZARRAY:
2376                 case MONO_TYPE_ARRAY:    
2377                         if (args [i]->type != STACK_OBJ)
2378                                 return 1;
2379                         continue;
2380                 case MONO_TYPE_I8:
2381                 case MONO_TYPE_U8:
2382                         if (args [i]->type != STACK_I8)
2383                                 return 1;
2384                         continue;
2385                 case MONO_TYPE_R4:
2386                         if (args [i]->type != cfg->r4_stack_type)
2387                                 return 1;
2388                         continue;
2389                 case MONO_TYPE_R8:
2390                         if (args [i]->type != STACK_R8)
2391                                 return 1;
2392                         continue;
2393                 case MONO_TYPE_VALUETYPE:
2394                         if (simple_type->data.klass->enumtype) {
2395                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2396                                 goto handle_enum;
2397                         }
2398                         if (args [i]->type != STACK_VTYPE)
2399                                 return 1;
2400                         continue;
2401                 case MONO_TYPE_TYPEDBYREF:
2402                         if (args [i]->type != STACK_VTYPE)
2403                                 return 1;
2404                         continue;
2405                 case MONO_TYPE_GENERICINST:
2406                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2407                         goto handle_enum;
2408                 case MONO_TYPE_VAR:
2409                 case MONO_TYPE_MVAR:
2410                         /* gsharedvt */
2411                         if (args [i]->type != STACK_VTYPE)
2412                                 return 1;
2413                         continue;
2414                 default:
2415                         g_error ("unknown type 0x%02x in check_call_signature",
2416                                  simple_type->type);
2417                 }
2418         }
2419         return 0;
2420 }
2421
2422 static int
2423 callvirt_to_call (int opcode)
2424 {
2425         switch (opcode) {
2426         case OP_CALL_MEMBASE:
2427                 return OP_CALL;
2428         case OP_VOIDCALL_MEMBASE:
2429                 return OP_VOIDCALL;
2430         case OP_FCALL_MEMBASE:
2431                 return OP_FCALL;
2432         case OP_RCALL_MEMBASE:
2433                 return OP_RCALL;
2434         case OP_VCALL_MEMBASE:
2435                 return OP_VCALL;
2436         case OP_LCALL_MEMBASE:
2437                 return OP_LCALL;
2438         default:
2439                 g_assert_not_reached ();
2440         }
2441
2442         return -1;
2443 }
2444
2445 /* Either METHOD or IMT_ARG needs to be set */
2446 static void
2447 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2448 {
2449         int method_reg;
2450
2451         if (COMPILE_LLVM (cfg)) {
2452                 method_reg = alloc_preg (cfg);
2453
2454                 if (imt_arg) {
2455                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2456                 } else if (cfg->compile_aot) {
2457                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2458                 } else {
2459                         MonoInst *ins;
2460                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2461                         ins->inst_p0 = method;
2462                         ins->dreg = method_reg;
2463                         MONO_ADD_INS (cfg->cbb, ins);
2464                 }
2465
2466 #ifdef ENABLE_LLVM
2467                 call->imt_arg_reg = method_reg;
2468 #endif
2469 #ifdef MONO_ARCH_IMT_REG
2470         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2471 #else
2472         /* Need this to keep the IMT arg alive */
2473         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2474 #endif
2475                 return;
2476         }
2477
2478 #ifdef MONO_ARCH_IMT_REG
2479         method_reg = alloc_preg (cfg);
2480
2481         if (imt_arg) {
2482                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2483         } else if (cfg->compile_aot) {
2484                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2485         } else {
2486                 MonoInst *ins;
2487                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2488                 ins->inst_p0 = method;
2489                 ins->dreg = method_reg;
2490                 MONO_ADD_INS (cfg->cbb, ins);
2491         }
2492
2493         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2494 #else
2495         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2496 #endif
2497 }
2498
2499 static MonoJumpInfo *
2500 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2501 {
2502         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2503
2504         ji->ip.i = ip;
2505         ji->type = type;
2506         ji->data.target = target;
2507
2508         return ji;
2509 }
2510
2511 static int
2512 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2513 {
2514         if (cfg->generic_sharing_context)
2515                 return mono_class_check_context_used (klass);
2516         else
2517                 return 0;
2518 }
2519
2520 static int
2521 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2522 {
2523         if (cfg->generic_sharing_context)
2524                 return mono_method_check_context_used (method);
2525         else
2526                 return 0;
2527 }
2528
2529 /*
2530  * check_method_sharing:
2531  *
2532  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2533  */
2534 static void
2535 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2536 {
2537         gboolean pass_vtable = FALSE;
2538         gboolean pass_mrgctx = FALSE;
2539
2540         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2541                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2542                 gboolean sharable = FALSE;
2543
2544                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2545                         sharable = TRUE;
2546                 } else {
2547                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2548                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2549                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2550
2551                         sharable = sharing_enabled && context_sharable;
2552                 }
2553
2554                 /*
2555                  * Pass vtable iff target method might
2556                  * be shared, which means that sharing
2557                  * is enabled for its class and its
2558                  * context is sharable (and it's not a
2559                  * generic method).
2560                  */
2561                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2562                         pass_vtable = TRUE;
2563         }
2564
2565         if (mini_method_get_context (cmethod) &&
2566                 mini_method_get_context (cmethod)->method_inst) {
2567                 g_assert (!pass_vtable);
2568
2569                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2570                         pass_mrgctx = TRUE;
2571                 } else {
2572                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2573                         MonoGenericContext *context = mini_method_get_context (cmethod);
2574                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2575
2576                         if (sharing_enabled && context_sharable)
2577                                 pass_mrgctx = TRUE;
2578                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2579                                 pass_mrgctx = TRUE;
2580                 }
2581         }
2582
2583         if (out_pass_vtable)
2584                 *out_pass_vtable = pass_vtable;
2585         if (out_pass_mrgctx)
2586                 *out_pass_mrgctx = pass_mrgctx;
2587 }
2588
2589 inline static MonoCallInst *
2590 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2591                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2592 {
2593         MonoType *sig_ret;
2594         MonoCallInst *call;
2595 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2596         int i;
2597 #endif
2598
2599         if (tail) {
2600                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2601
2602                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2603         } else
2604                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual, cfg->generic_sharing_context));
2605
2606         call->args = args;
2607         call->signature = sig;
2608         call->rgctx_reg = rgctx;
2609         sig_ret = mini_get_underlying_type (cfg, sig->ret);
2610
2611         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2612
2613         if (tail) {
2614                 if (mini_type_is_vtype (cfg, sig_ret)) {
2615                         call->vret_var = cfg->vret_addr;
2616                         //g_assert_not_reached ();
2617                 }
2618         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2619                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2620                 MonoInst *loada;
2621
2622                 temp->backend.is_pinvoke = sig->pinvoke;
2623
2624                 /*
2625                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2626                  * address of return value to increase optimization opportunities.
2627                  * Before vtype decomposition, the dreg of the call ins itself represents the
2628                  * fact the call modifies the return value. After decomposition, the call will
2629                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2630                  * will be transformed into an LDADDR.
2631                  */
2632                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2633                 loada->dreg = alloc_preg (cfg);
2634                 loada->inst_p0 = temp;
2635                 /* We reference the call too since call->dreg could change during optimization */
2636                 loada->inst_p1 = call;
2637                 MONO_ADD_INS (cfg->cbb, loada);
2638
2639                 call->inst.dreg = temp->dreg;
2640
2641                 call->vret_var = loada;
2642         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2643                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2644
2645 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2646         if (COMPILE_SOFT_FLOAT (cfg)) {
2647                 /* 
2648                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2649                  * an icall, but that cannot be done during the call sequence since it would clobber
2650                  * the call registers + the stack. So we do it before emitting the call.
2651                  */
2652                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2653                         MonoType *t;
2654                         MonoInst *in = call->args [i];
2655
2656                         if (i >= sig->hasthis)
2657                                 t = sig->params [i - sig->hasthis];
2658                         else
2659                                 t = &mono_defaults.int_class->byval_arg;
2660                         t = mono_type_get_underlying_type (t);
2661
2662                         if (!t->byref && t->type == MONO_TYPE_R4) {
2663                                 MonoInst *iargs [1];
2664                                 MonoInst *conv;
2665
2666                                 iargs [0] = in;
2667                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2668
2669                                 /* The result will be in an int vreg */
2670                                 call->args [i] = conv;
2671                         }
2672                 }
2673         }
2674 #endif
2675
2676         call->need_unbox_trampoline = unbox_trampoline;
2677
2678 #ifdef ENABLE_LLVM
2679         if (COMPILE_LLVM (cfg))
2680                 mono_llvm_emit_call (cfg, call);
2681         else
2682                 mono_arch_emit_call (cfg, call);
2683 #else
2684         mono_arch_emit_call (cfg, call);
2685 #endif
2686
2687         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2688         cfg->flags |= MONO_CFG_HAS_CALLS;
2689         
2690         return call;
2691 }
2692
2693 static void
2694 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2695 {
2696 #ifdef MONO_ARCH_RGCTX_REG
2697         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2698         cfg->uses_rgctx_reg = TRUE;
2699         call->rgctx_reg = TRUE;
2700 #ifdef ENABLE_LLVM
2701         call->rgctx_arg_reg = rgctx_reg;
2702 #endif
2703 #else
2704         NOT_IMPLEMENTED;
2705 #endif
2706 }       
2707
2708 inline static MonoInst*
2709 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2710 {
2711         MonoCallInst *call;
2712         MonoInst *ins;
2713         int rgctx_reg = -1;
2714         gboolean check_sp = FALSE;
2715
2716         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2717                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2718
2719                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2720                         check_sp = TRUE;
2721         }
2722
2723         if (rgctx_arg) {
2724                 rgctx_reg = mono_alloc_preg (cfg);
2725                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2726         }
2727
2728         if (check_sp) {
2729                 if (!cfg->stack_inbalance_var)
2730                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2731
2732                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2733                 ins->dreg = cfg->stack_inbalance_var->dreg;
2734                 MONO_ADD_INS (cfg->cbb, ins);
2735         }
2736
2737         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2738
2739         call->inst.sreg1 = addr->dreg;
2740
2741         if (imt_arg)
2742                 emit_imt_argument (cfg, call, NULL, imt_arg);
2743
2744         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2745
2746         if (check_sp) {
2747                 int sp_reg;
2748
2749                 sp_reg = mono_alloc_preg (cfg);
2750
2751                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2752                 ins->dreg = sp_reg;
2753                 MONO_ADD_INS (cfg->cbb, ins);
2754
2755                 /* Restore the stack so we don't crash when throwing the exception */
2756                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2757                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2758                 MONO_ADD_INS (cfg->cbb, ins);
2759
2760                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2761                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2762         }
2763
2764         if (rgctx_arg)
2765                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2766
2767         return (MonoInst*)call;
2768 }
2769
2770 static MonoInst*
2771 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2772
2773 static MonoInst*
2774 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2775 static MonoInst*
2776 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2777
2778 static MonoInst*
2779 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2780                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2781 {
2782 #ifndef DISABLE_REMOTING
2783         gboolean might_be_remote = FALSE;
2784 #endif
2785         gboolean virtual = this != NULL;
2786         gboolean enable_for_aot = TRUE;
2787         int context_used;
2788         MonoCallInst *call;
2789         int rgctx_reg = 0;
2790         gboolean need_unbox_trampoline;
2791
2792         if (!sig)
2793                 sig = mono_method_signature (method);
2794
2795         if (rgctx_arg) {
2796                 rgctx_reg = mono_alloc_preg (cfg);
2797                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2798         }
2799
2800         if (method->string_ctor) {
2801                 /* Create the real signature */
2802                 /* FIXME: Cache these */
2803                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2804                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2805
2806                 sig = ctor_sig;
2807         }
2808
2809         context_used = mini_method_check_context_used (cfg, method);
2810
2811 #ifndef DISABLE_REMOTING
2812         might_be_remote = this && sig->hasthis &&
2813                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2814                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2815
2816         if (might_be_remote && context_used) {
2817                 MonoInst *addr;
2818
2819                 g_assert (cfg->generic_sharing_context);
2820
2821                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2822
2823                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2824         }
2825 #endif
2826
2827         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2828
2829         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2830
2831 #ifndef DISABLE_REMOTING
2832         if (might_be_remote)
2833                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2834         else
2835 #endif
2836                 call->method = method;
2837         call->inst.flags |= MONO_INST_HAS_METHOD;
2838         call->inst.inst_left = this;
2839         call->tail_call = tail;
2840
2841         if (virtual) {
2842                 int vtable_reg, slot_reg, this_reg;
2843                 int offset;
2844
2845                 this_reg = this->dreg;
2846
2847                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2848                         MonoInst *dummy_use;
2849
2850                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2851
2852                         /* Make a call to delegate->invoke_impl */
2853                         call->inst.inst_basereg = this_reg;
2854                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2855                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2856
2857                         /* We must emit a dummy use here because the delegate trampoline will
2858                         replace the 'this' argument with the delegate target making this activation
2859                         no longer a root for the delegate.
2860                         This is an issue for delegates that target collectible code such as dynamic
2861                         methods of GC'able assemblies.
2862
2863                         For a test case look into #667921.
2864
2865                         FIXME: a dummy use is not the best way to do it as the local register allocator
2866                         will put it on a caller save register and spil it around the call. 
2867                         Ideally, we would either put it on a callee save register or only do the store part.  
2868                          */
2869                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2870
2871                         return (MonoInst*)call;
2872                 }
2873
2874                 if ((!cfg->compile_aot || enable_for_aot) && 
2875                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2876                          (MONO_METHOD_IS_FINAL (method) &&
2877                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2878                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2879                         /* 
2880                          * the method is not virtual, we just need to ensure this is not null
2881                          * and then we can call the method directly.
2882                          */
2883 #ifndef DISABLE_REMOTING
2884                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2885                                 /* 
2886                                  * The check above ensures method is not gshared, this is needed since
2887                                  * gshared methods can't have wrappers.
2888                                  */
2889                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2890                         }
2891 #endif
2892
2893                         if (!method->string_ctor)
2894                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2895
2896                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2897                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2898                         /*
2899                          * the method is virtual, but we can statically dispatch since either
2900                          * it's class or the method itself are sealed.
2901                          * But first we need to ensure it's not a null reference.
2902                          */
2903                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2904
2905                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2906                 } else {
2907                         vtable_reg = alloc_preg (cfg);
2908                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2909                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2910                                 slot_reg = -1;
2911                                 if (mono_use_imt) {
2912                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2913                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2914                                         slot_reg = vtable_reg;
2915                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2916                                 }
2917                                 if (slot_reg == -1) {
2918                                         slot_reg = alloc_preg (cfg);
2919                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2920                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2921                                 }
2922                         } else {
2923                                 slot_reg = vtable_reg;
2924                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2925                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2926                                 if (imt_arg) {
2927                                         g_assert (mono_method_signature (method)->generic_param_count);
2928                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2929                                 }
2930                         }
2931
2932                         call->inst.sreg1 = slot_reg;
2933                         call->inst.inst_offset = offset;
2934                         call->virtual = TRUE;
2935                 }
2936         }
2937
2938         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2939
2940         if (rgctx_arg)
2941                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2942
2943         return (MonoInst*)call;
2944 }
2945
2946 MonoInst*
2947 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2948 {
2949         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2950 }
2951
2952 MonoInst*
2953 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2954                                            MonoInst **args)
2955 {
2956         MonoCallInst *call;
2957
2958         g_assert (sig);
2959
2960         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2961         call->fptr = func;
2962
2963         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2964
2965         return (MonoInst*)call;
2966 }
2967
2968 MonoInst*
2969 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2970 {
2971         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2972
2973         g_assert (info);
2974
2975         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2976 }
2977
2978 /*
2979  * mono_emit_abs_call:
2980  *
2981  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2982  */
2983 inline static MonoInst*
2984 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2985                                         MonoMethodSignature *sig, MonoInst **args)
2986 {
2987         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2988         MonoInst *ins;
2989
2990         /* 
2991          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2992          * handle it.
2993          */
2994         if (cfg->abs_patches == NULL)
2995                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2996         g_hash_table_insert (cfg->abs_patches, ji, ji);
2997         ins = mono_emit_native_call (cfg, ji, sig, args);
2998         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2999         return ins;
3000 }
3001
3002 MonoInst*
3003 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args, MonoBasicBlock **out_cbb)
3004 {
3005         gboolean no_wrapper = FALSE;
3006
3007         /*
3008          * Call the jit icall without a wrapper if possible.
3009          * The wrapper is needed for the following reasons:
3010          * - to handle exceptions thrown using mono_raise_exceptions () from the
3011          *   icall function. The EH code needs the lmf frame pushed by the
3012          *   wrapper to be able to unwind back to managed code.
3013          * - to be able to do stack walks for asynchronously suspended
3014          *   threads when debugging.
3015          */
3016         if (info->no_raise) {
3017                 if (cfg->compile_aot) {
3018                         // FIXME: This might be loaded into a runtime during debugging
3019                         // even if it is not compiled using 'soft-debug'.
3020                 } else {
3021                         no_wrapper = TRUE;
3022                         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3023                         if ((cfg->compile_llvm && SIZEOF_VOID_P == 8) || cfg->gen_seq_points_debug_data)
3024                                 no_wrapper = FALSE;
3025                 }
3026         }
3027
3028         if (no_wrapper) {
3029                 char *name;
3030                 int costs;
3031
3032                 if (!info->wrapper_method) {
3033                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3034                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3035                         g_free (name);
3036                         mono_memory_barrier ();
3037                 }
3038
3039                 /*
3040                  * Inline the wrapper method, which is basically a call to the C icall, and
3041                  * an exception check.
3042                  */
3043                 costs = inline_method (cfg, info->wrapper_method, NULL,
3044                                                            args, NULL, cfg->real_offset, TRUE, out_cbb);
3045                 g_assert (costs > 0);
3046                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3047
3048                 return args [0];
3049         } else {
3050                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3051         }
3052 }
3053  
3054 static MonoInst*
3055 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3056 {
3057         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3058                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3059                         int widen_op = -1;
3060
3061                         /* 
3062                          * Native code might return non register sized integers 
3063                          * without initializing the upper bits.
3064                          */
3065                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3066                         case OP_LOADI1_MEMBASE:
3067                                 widen_op = OP_ICONV_TO_I1;
3068                                 break;
3069                         case OP_LOADU1_MEMBASE:
3070                                 widen_op = OP_ICONV_TO_U1;
3071                                 break;
3072                         case OP_LOADI2_MEMBASE:
3073                                 widen_op = OP_ICONV_TO_I2;
3074                                 break;
3075                         case OP_LOADU2_MEMBASE:
3076                                 widen_op = OP_ICONV_TO_U2;
3077                                 break;
3078                         default:
3079                                 break;
3080                         }
3081
3082                         if (widen_op != -1) {
3083                                 int dreg = alloc_preg (cfg);
3084                                 MonoInst *widen;
3085
3086                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3087                                 widen->type = ins->type;
3088                                 ins = widen;
3089                         }
3090                 }
3091         }
3092
3093         return ins;
3094 }
3095
3096 static MonoMethod*
3097 get_memcpy_method (void)
3098 {
3099         static MonoMethod *memcpy_method = NULL;
3100         if (!memcpy_method) {
3101                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3102                 if (!memcpy_method)
3103                         g_error ("Old corlib found. Install a new one");
3104         }
3105         return memcpy_method;
3106 }
3107
3108 static void
3109 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3110 {
3111         MonoClassField *field;
3112         gpointer iter = NULL;
3113
3114         while ((field = mono_class_get_fields (klass, &iter))) {
3115                 int foffset;
3116
3117                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3118                         continue;
3119                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3120                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3121                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3122                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3123                 } else {
3124                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3125                         if (field_class->has_references)
3126                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3127                 }
3128         }
3129 }
3130
3131 static void
3132 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3133 {
3134         int card_table_shift_bits;
3135         gpointer card_table_mask;
3136         guint8 *card_table;
3137         MonoInst *dummy_use;
3138         int nursery_shift_bits;
3139         size_t nursery_size;
3140         gboolean has_card_table_wb = FALSE;
3141
3142         if (!cfg->gen_write_barriers)
3143                 return;
3144
3145         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3146
3147         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3148
3149 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3150         has_card_table_wb = TRUE;
3151 #endif
3152
3153         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3154                 MonoInst *wbarrier;
3155
3156                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3157                 wbarrier->sreg1 = ptr->dreg;
3158                 wbarrier->sreg2 = value->dreg;
3159                 MONO_ADD_INS (cfg->cbb, wbarrier);
3160         } else if (card_table) {
3161                 int offset_reg = alloc_preg (cfg);
3162                 int card_reg  = alloc_preg (cfg);
3163                 MonoInst *ins;
3164
3165                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3166                 if (card_table_mask)
3167                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3168
3169                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3170                  * IMM's larger than 32bits.
3171                  */
3172                 if (cfg->compile_aot) {
3173                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3174                 } else {
3175                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3176                         ins->inst_p0 = card_table;
3177                         ins->dreg = card_reg;
3178                         MONO_ADD_INS (cfg->cbb, ins);
3179                 }
3180
3181                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3182                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3183         } else {
3184                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3185                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3186         }
3187
3188         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3189 }
3190
3191 static gboolean
3192 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3193 {
3194         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3195         unsigned need_wb = 0;
3196
3197         if (align == 0)
3198                 align = 4;
3199
3200         /*types with references can't have alignment smaller than sizeof(void*) */
3201         if (align < SIZEOF_VOID_P)
3202                 return FALSE;
3203
3204         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3205         if (size > 32 * SIZEOF_VOID_P)
3206                 return FALSE;
3207
3208         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3209
3210         /* We don't unroll more than 5 stores to avoid code bloat. */
3211         if (size > 5 * SIZEOF_VOID_P) {
3212                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3213                 size += (SIZEOF_VOID_P - 1);
3214                 size &= ~(SIZEOF_VOID_P - 1);
3215
3216                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3217                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3218                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3219                 return TRUE;
3220         }
3221
3222         destreg = iargs [0]->dreg;
3223         srcreg = iargs [1]->dreg;
3224         offset = 0;
3225
3226         dest_ptr_reg = alloc_preg (cfg);
3227         tmp_reg = alloc_preg (cfg);
3228
3229         /*tmp = dreg*/
3230         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3231
3232         while (size >= SIZEOF_VOID_P) {
3233                 MonoInst *load_inst;
3234                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3235                 load_inst->dreg = tmp_reg;
3236                 load_inst->inst_basereg = srcreg;
3237                 load_inst->inst_offset = offset;
3238                 MONO_ADD_INS (cfg->cbb, load_inst);
3239
3240                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3241
3242                 if (need_wb & 0x1)
3243                         emit_write_barrier (cfg, iargs [0], load_inst);
3244
3245                 offset += SIZEOF_VOID_P;
3246                 size -= SIZEOF_VOID_P;
3247                 need_wb >>= 1;
3248
3249                 /*tmp += sizeof (void*)*/
3250                 if (size >= SIZEOF_VOID_P) {
3251                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3252                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3253                 }
3254         }
3255
3256         /* Those cannot be references since size < sizeof (void*) */
3257         while (size >= 4) {
3258                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3259                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3260                 offset += 4;
3261                 size -= 4;
3262         }
3263
3264         while (size >= 2) {
3265                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3266                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3267                 offset += 2;
3268                 size -= 2;
3269         }
3270
3271         while (size >= 1) {
3272                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3273                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3274                 offset += 1;
3275                 size -= 1;
3276         }
3277
3278         return TRUE;
3279 }
3280
3281 /*
3282  * Emit code to copy a valuetype of type @klass whose address is stored in
3283  * @src->dreg to memory whose address is stored at @dest->dreg.
3284  */
3285 void
3286 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3287 {
3288         MonoInst *iargs [4];
3289         int context_used, n;
3290         guint32 align = 0;
3291         MonoMethod *memcpy_method;
3292         MonoInst *size_ins = NULL;
3293         MonoInst *memcpy_ins = NULL;
3294
3295         g_assert (klass);
3296         if (cfg->generic_sharing_context)
3297                 klass = mono_class_from_mono_type (mini_get_underlying_type (cfg, &klass->byval_arg));
3298
3299         /*
3300          * This check breaks with spilled vars... need to handle it during verification anyway.
3301          * g_assert (klass && klass == src->klass && klass == dest->klass);
3302          */
3303
3304         if (mini_is_gsharedvt_klass (cfg, klass)) {
3305                 g_assert (!native);
3306                 context_used = mini_class_check_context_used (cfg, klass);
3307                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3308                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3309         }
3310
3311         if (native)
3312                 n = mono_class_native_size (klass, &align);
3313         else
3314                 n = mono_class_value_size (klass, &align);
3315
3316         /* if native is true there should be no references in the struct */
3317         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3318                 /* Avoid barriers when storing to the stack */
3319                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3320                           (dest->opcode == OP_LDADDR))) {
3321                         int context_used;
3322
3323                         iargs [0] = dest;
3324                         iargs [1] = src;
3325
3326                         context_used = mini_class_check_context_used (cfg, klass);
3327
3328                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3329                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3330                                 return;
3331                         } else if (context_used) {
3332                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3333                         }  else {
3334                                 if (cfg->compile_aot) {
3335                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3336                                 } else {
3337                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3338                                         mono_class_compute_gc_descriptor (klass);
3339                                 }
3340                         }
3341
3342                         if (size_ins)
3343                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3344                         else
3345                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3346                         return;
3347                 }
3348         }
3349
3350         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3351                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3352                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3353         } else {
3354                 iargs [0] = dest;
3355                 iargs [1] = src;
3356                 if (size_ins)
3357                         iargs [2] = size_ins;
3358                 else
3359                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3360                 
3361                 memcpy_method = get_memcpy_method ();
3362                 if (memcpy_ins)
3363                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3364                 else
3365                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3366         }
3367 }
3368
3369 static MonoMethod*
3370 get_memset_method (void)
3371 {
3372         static MonoMethod *memset_method = NULL;
3373         if (!memset_method) {
3374                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3375                 if (!memset_method)
3376                         g_error ("Old corlib found. Install a new one");
3377         }
3378         return memset_method;
3379 }
3380
3381 void
3382 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3383 {
3384         MonoInst *iargs [3];
3385         int n, context_used;
3386         guint32 align;
3387         MonoMethod *memset_method;
3388         MonoInst *size_ins = NULL;
3389         MonoInst *bzero_ins = NULL;
3390         static MonoMethod *bzero_method;
3391
3392         /* FIXME: Optimize this for the case when dest is an LDADDR */
3393         mono_class_init (klass);
3394         if (mini_is_gsharedvt_klass (cfg, klass)) {
3395                 context_used = mini_class_check_context_used (cfg, klass);
3396                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3397                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3398                 if (!bzero_method)
3399                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3400                 g_assert (bzero_method);
3401                 iargs [0] = dest;
3402                 iargs [1] = size_ins;
3403                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3404                 return;
3405         }
3406
3407         n = mono_class_value_size (klass, &align);
3408
3409         if (n <= sizeof (gpointer) * 8) {
3410                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3411         }
3412         else {
3413                 memset_method = get_memset_method ();
3414                 iargs [0] = dest;
3415                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3416                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3417                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3418         }
3419 }
3420
3421 static MonoInst*
3422 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3423 {
3424         MonoInst *this = NULL;
3425
3426         g_assert (cfg->generic_sharing_context);
3427
3428         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3429                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3430                         !method->klass->valuetype)
3431                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3432
3433         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3434                 MonoInst *mrgctx_loc, *mrgctx_var;
3435
3436                 g_assert (!this);
3437                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3438
3439                 mrgctx_loc = mono_get_vtable_var (cfg);
3440                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3441
3442                 return mrgctx_var;
3443         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3444                 MonoInst *vtable_loc, *vtable_var;
3445
3446                 g_assert (!this);
3447
3448                 vtable_loc = mono_get_vtable_var (cfg);
3449                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3450
3451                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3452                         MonoInst *mrgctx_var = vtable_var;
3453                         int vtable_reg;
3454
3455                         vtable_reg = alloc_preg (cfg);
3456                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3457                         vtable_var->type = STACK_PTR;
3458                 }
3459
3460                 return vtable_var;
3461         } else {
3462                 MonoInst *ins;
3463                 int vtable_reg;
3464         
3465                 vtable_reg = alloc_preg (cfg);
3466                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3467                 return ins;
3468         }
3469 }
3470
3471 static MonoJumpInfoRgctxEntry *
3472 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3473 {
3474         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3475         res->method = method;
3476         res->in_mrgctx = in_mrgctx;
3477         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3478         res->data->type = patch_type;
3479         res->data->data.target = patch_data;
3480         res->info_type = info_type;
3481
3482         return res;
3483 }
3484
3485 static inline MonoInst*
3486 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3487 {
3488         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3489 }
3490
3491 static MonoInst*
3492 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3493                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3494 {
3495         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);
3496         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3497
3498         return emit_rgctx_fetch (cfg, rgctx, entry);
3499 }
3500
3501 static MonoInst*
3502 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3503                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3504 {
3505         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);
3506         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3507
3508         return emit_rgctx_fetch (cfg, rgctx, entry);
3509 }
3510
3511 static MonoInst*
3512 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3513                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3514 {
3515         MonoJumpInfoGSharedVtCall *call_info;
3516         MonoJumpInfoRgctxEntry *entry;
3517         MonoInst *rgctx;
3518
3519         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3520         call_info->sig = sig;
3521         call_info->method = cmethod;
3522
3523         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);
3524         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3525
3526         return emit_rgctx_fetch (cfg, rgctx, entry);
3527 }
3528
3529
3530 static MonoInst*
3531 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3532                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3533 {
3534         MonoJumpInfoRgctxEntry *entry;
3535         MonoInst *rgctx;
3536
3537         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);
3538         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3539
3540         return emit_rgctx_fetch (cfg, rgctx, entry);
3541 }
3542
3543 /*
3544  * emit_get_rgctx_method:
3545  *
3546  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3547  * normal constants, else emit a load from the rgctx.
3548  */
3549 static MonoInst*
3550 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3551                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3552 {
3553         if (!context_used) {
3554                 MonoInst *ins;
3555
3556                 switch (rgctx_type) {
3557                 case MONO_RGCTX_INFO_METHOD:
3558                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3559                         return ins;
3560                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3561                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3562                         return ins;
3563                 default:
3564                         g_assert_not_reached ();
3565                 }
3566         } else {
3567                 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);
3568                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3569
3570                 return emit_rgctx_fetch (cfg, rgctx, entry);
3571         }
3572 }
3573
3574 static MonoInst*
3575 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3576                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3577 {
3578         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);
3579         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3580
3581         return emit_rgctx_fetch (cfg, rgctx, entry);
3582 }
3583
3584 static int
3585 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3586 {
3587         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3588         MonoRuntimeGenericContextInfoTemplate *template;
3589         int i, idx;
3590
3591         g_assert (info);
3592
3593         for (i = 0; i < info->num_entries; ++i) {
3594                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3595
3596                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3597                         return i;
3598         }
3599
3600         if (info->num_entries == info->count_entries) {
3601                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3602                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3603
3604                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3605
3606                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3607                 info->entries = new_entries;
3608                 info->count_entries = new_count_entries;
3609         }
3610
3611         idx = info->num_entries;
3612         template = &info->entries [idx];
3613         template->info_type = rgctx_type;
3614         template->data = data;
3615
3616         info->num_entries ++;
3617
3618         return idx;
3619 }
3620
3621 /*
3622  * emit_get_gsharedvt_info:
3623  *
3624  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3625  */
3626 static MonoInst*
3627 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3628 {
3629         MonoInst *ins;
3630         int idx, dreg;
3631
3632         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3633         /* Load info->entries [idx] */
3634         dreg = alloc_preg (cfg);
3635         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3636
3637         return ins;
3638 }
3639
3640 static MonoInst*
3641 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3642 {
3643         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3644 }
3645
3646 /*
3647  * On return the caller must check @klass for load errors.
3648  */
3649 static void
3650 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3651 {
3652         MonoInst *vtable_arg;
3653         MonoCallInst *call;
3654         int context_used;
3655
3656         context_used = mini_class_check_context_used (cfg, klass);
3657
3658         if (context_used) {
3659                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3660                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3661         } else {
3662                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3663
3664                 if (!vtable)
3665                         return;
3666                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3667         }
3668
3669         if (COMPILE_LLVM (cfg))
3670                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3671         else
3672                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3673 #ifdef MONO_ARCH_VTABLE_REG
3674         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3675         cfg->uses_vtable_reg = TRUE;
3676 #else
3677         NOT_IMPLEMENTED;
3678 #endif
3679 }
3680
3681 static void
3682 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3683 {
3684         MonoInst *ins;
3685
3686         if (cfg->gen_seq_points && cfg->method == method) {
3687                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3688                 if (nonempty_stack)
3689                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3690                 MONO_ADD_INS (cfg->cbb, ins);
3691         }
3692 }
3693
3694 static void
3695 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3696 {
3697         if (mini_get_debug_options ()->better_cast_details) {
3698                 int vtable_reg = alloc_preg (cfg);
3699                 int klass_reg = alloc_preg (cfg);
3700                 MonoBasicBlock *is_null_bb = NULL;
3701                 MonoInst *tls_get;
3702                 int to_klass_reg, context_used;
3703
3704                 if (null_check) {
3705                         NEW_BBLOCK (cfg, is_null_bb);
3706
3707                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3708                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3709                 }
3710
3711                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3712                 if (!tls_get) {
3713                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3714                         exit (1);
3715                 }
3716
3717                 MONO_ADD_INS (cfg->cbb, tls_get);
3718                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3719                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3720
3721                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3722
3723                 context_used = mini_class_check_context_used (cfg, klass);
3724                 if (context_used) {
3725                         MonoInst *class_ins;
3726
3727                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3728                         to_klass_reg = class_ins->dreg;
3729                 } else {
3730                         to_klass_reg = alloc_preg (cfg);
3731                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3732                 }
3733                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3734
3735                 if (null_check) {
3736                         MONO_START_BB (cfg, is_null_bb);
3737                         if (out_bblock)
3738                                 *out_bblock = cfg->cbb;
3739                 }
3740         }
3741 }
3742
3743 static void
3744 reset_cast_details (MonoCompile *cfg)
3745 {
3746         /* Reset the variables holding the cast details */
3747         if (mini_get_debug_options ()->better_cast_details) {
3748                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3749
3750                 MONO_ADD_INS (cfg->cbb, tls_get);
3751                 /* It is enough to reset the from field */
3752                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3753         }
3754 }
3755
3756 /*
3757  * On return the caller must check @array_class for load errors
3758  */
3759 static void
3760 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3761 {
3762         int vtable_reg = alloc_preg (cfg);
3763         int context_used;
3764
3765         context_used = mini_class_check_context_used (cfg, array_class);
3766
3767         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3768
3769         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3770
3771         if (cfg->opt & MONO_OPT_SHARED) {
3772                 int class_reg = alloc_preg (cfg);
3773                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3774                 if (cfg->compile_aot) {
3775                         int klass_reg = alloc_preg (cfg);
3776                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3777                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3778                 } else {
3779                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3780                 }
3781         } else if (context_used) {
3782                 MonoInst *vtable_ins;
3783
3784                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3785                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3786         } else {
3787                 if (cfg->compile_aot) {
3788                         int vt_reg;
3789                         MonoVTable *vtable;
3790
3791                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3792                                 return;
3793                         vt_reg = alloc_preg (cfg);
3794                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3795                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3796                 } else {
3797                         MonoVTable *vtable;
3798                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3799                                 return;
3800                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3801                 }
3802         }
3803         
3804         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3805
3806         reset_cast_details (cfg);
3807 }
3808
3809 /**
3810  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3811  * generic code is generated.
3812  */
3813 static MonoInst*
3814 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3815 {
3816         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3817
3818         if (context_used) {
3819                 MonoInst *rgctx, *addr;
3820
3821                 /* FIXME: What if the class is shared?  We might not
3822                    have to get the address of the method from the
3823                    RGCTX. */
3824                 addr = emit_get_rgctx_method (cfg, context_used, method,
3825                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3826
3827                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3828
3829                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3830         } else {
3831                 gboolean pass_vtable, pass_mrgctx;
3832                 MonoInst *rgctx_arg = NULL;
3833
3834                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3835                 g_assert (!pass_mrgctx);
3836
3837                 if (pass_vtable) {
3838                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3839
3840                         g_assert (vtable);
3841                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3842                 }
3843
3844                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3845         }
3846 }
3847
3848 static MonoInst*
3849 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3850 {
3851         MonoInst *add;
3852         int obj_reg;
3853         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3854         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3855         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3856         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3857
3858         obj_reg = sp [0]->dreg;
3859         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3860         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3861
3862         /* FIXME: generics */
3863         g_assert (klass->rank == 0);
3864                         
3865         // Check rank == 0
3866         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3867         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3868
3869         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3870         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3871
3872         if (context_used) {
3873                 MonoInst *element_class;
3874
3875                 /* This assertion is from the unboxcast insn */
3876                 g_assert (klass->rank == 0);
3877
3878                 element_class = emit_get_rgctx_klass (cfg, context_used,
3879                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3880
3881                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3882                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3883         } else {
3884                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3885                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3886                 reset_cast_details (cfg);
3887         }
3888
3889         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3890         MONO_ADD_INS (cfg->cbb, add);
3891         add->type = STACK_MP;
3892         add->klass = klass;
3893
3894         return add;
3895 }
3896
3897 static MonoInst*
3898 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3899 {
3900         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3901         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3902         MonoInst *ins;
3903         int dreg, addr_reg;
3904
3905         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3906
3907         /* obj */
3908         args [0] = obj;
3909
3910         /* klass */
3911         args [1] = klass_inst;
3912
3913         /* CASTCLASS */
3914         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3915
3916         NEW_BBLOCK (cfg, is_ref_bb);
3917         NEW_BBLOCK (cfg, is_nullable_bb);
3918         NEW_BBLOCK (cfg, end_bb);
3919         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3920         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3921         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3922
3923         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3924         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3925
3926         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3927         addr_reg = alloc_dreg (cfg, STACK_MP);
3928
3929         /* Non-ref case */
3930         /* UNBOX */
3931         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3932         MONO_ADD_INS (cfg->cbb, addr);
3933
3934         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3935
3936         /* Ref case */
3937         MONO_START_BB (cfg, is_ref_bb);
3938
3939         /* Save the ref to a temporary */
3940         dreg = alloc_ireg (cfg);
3941         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3942         addr->dreg = addr_reg;
3943         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3944         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3945
3946         /* Nullable case */
3947         MONO_START_BB (cfg, is_nullable_bb);
3948
3949         {
3950                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3951                 MonoInst *unbox_call;
3952                 MonoMethodSignature *unbox_sig;
3953                 MonoInst *var;
3954
3955                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3956
3957                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3958                 unbox_sig->ret = &klass->byval_arg;
3959                 unbox_sig->param_count = 1;
3960                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3961                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3962
3963                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3964                 addr->dreg = addr_reg;
3965         }
3966
3967         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3968
3969         /* End */
3970         MONO_START_BB (cfg, end_bb);
3971
3972         /* LDOBJ */
3973         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3974
3975         *out_cbb = cfg->cbb;
3976
3977         return ins;
3978 }
3979
3980 /*
3981  * Returns NULL and set the cfg exception on error.
3982  */
3983 static MonoInst*
3984 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3985 {
3986         MonoInst *iargs [2];
3987         void *alloc_ftn;
3988
3989         if (context_used) {
3990                 MonoInst *data;
3991                 int rgctx_info;
3992                 MonoInst *iargs [2];
3993                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3994
3995                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3996
3997                 if (cfg->opt & MONO_OPT_SHARED)
3998                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3999                 else
4000                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4001                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4002
4003                 if (cfg->opt & MONO_OPT_SHARED) {
4004                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4005                         iargs [1] = data;
4006                         alloc_ftn = mono_object_new;
4007                 } else {
4008                         iargs [0] = data;
4009                         alloc_ftn = mono_object_new_specific;
4010                 }
4011
4012                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4013                         if (known_instance_size)
4014                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4015                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4016                 }
4017
4018                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4019         }
4020
4021         if (cfg->opt & MONO_OPT_SHARED) {
4022                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4023                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4024
4025                 alloc_ftn = mono_object_new;
4026         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4027                 /* This happens often in argument checking code, eg. throw new FooException... */
4028                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4029                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4030                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4031         } else {
4032                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4033                 MonoMethod *managed_alloc = NULL;
4034                 gboolean pass_lw;
4035
4036                 if (!vtable) {
4037                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4038                         cfg->exception_ptr = klass;
4039                         return NULL;
4040                 }
4041
4042 #ifndef MONO_CROSS_COMPILE
4043                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4044 #endif
4045
4046                 if (managed_alloc) {
4047                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4048                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (klass->instance_size));
4049                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4050                 }
4051                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4052                 if (pass_lw) {
4053                         guint32 lw = vtable->klass->instance_size;
4054                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4055                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4056                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4057                 }
4058                 else {
4059                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4060                 }
4061         }
4062
4063         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4064 }
4065         
4066 /*
4067  * Returns NULL and set the cfg exception on error.
4068  */     
4069 static MonoInst*
4070 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
4071 {
4072         MonoInst *alloc, *ins;
4073
4074         *out_cbb = cfg->cbb;
4075
4076         if (mono_class_is_nullable (klass)) {
4077                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4078
4079                 if (context_used) {
4080                         /* FIXME: What if the class is shared?  We might not
4081                            have to get the method address from the RGCTX. */
4082                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4083                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4084                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4085
4086                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4087                 } else {
4088                         gboolean pass_vtable, pass_mrgctx;
4089                         MonoInst *rgctx_arg = NULL;
4090
4091                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4092                         g_assert (!pass_mrgctx);
4093
4094                         if (pass_vtable) {
4095                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4096
4097                                 g_assert (vtable);
4098                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4099                         }
4100
4101                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4102                 }
4103         }
4104
4105         if (mini_is_gsharedvt_klass (cfg, klass)) {
4106                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4107                 MonoInst *res, *is_ref, *src_var, *addr;
4108                 int addr_reg, dreg;
4109
4110                 dreg = alloc_ireg (cfg);
4111
4112                 NEW_BBLOCK (cfg, is_ref_bb);
4113                 NEW_BBLOCK (cfg, is_nullable_bb);
4114                 NEW_BBLOCK (cfg, end_bb);
4115                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4116                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4117                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4118
4119                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4120                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4121
4122                 /* Non-ref case */
4123                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4124                 if (!alloc)
4125                         return NULL;
4126                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4127                 ins->opcode = OP_STOREV_MEMBASE;
4128
4129                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4130                 res->type = STACK_OBJ;
4131                 res->klass = klass;
4132                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4133                 
4134                 /* Ref case */
4135                 MONO_START_BB (cfg, is_ref_bb);
4136                 addr_reg = alloc_ireg (cfg);
4137
4138                 /* val is a vtype, so has to load the value manually */
4139                 src_var = get_vreg_to_inst (cfg, val->dreg);
4140                 if (!src_var)
4141                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4142                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4143                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4144                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4145
4146                 /* Nullable case */
4147                 MONO_START_BB (cfg, is_nullable_bb);
4148
4149                 {
4150                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4151                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4152                         MonoInst *box_call;
4153                         MonoMethodSignature *box_sig;
4154
4155                         /*
4156                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4157                          * construct that method at JIT time, so have to do things by hand.
4158                          */
4159                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4160                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4161                         box_sig->param_count = 1;
4162                         box_sig->params [0] = &klass->byval_arg;
4163                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4164                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4165                         res->type = STACK_OBJ;
4166                         res->klass = klass;
4167                 }
4168
4169                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4170
4171                 MONO_START_BB (cfg, end_bb);
4172
4173                 *out_cbb = cfg->cbb;
4174
4175                 return res;
4176         } else {
4177                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4178                 if (!alloc)
4179                         return NULL;
4180
4181                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4182                 return alloc;
4183         }
4184 }
4185
4186
4187 static gboolean
4188 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4189 {
4190         int i;
4191         MonoGenericContainer *container;
4192         MonoGenericInst *ginst;
4193
4194         if (klass->generic_class) {
4195                 container = klass->generic_class->container_class->generic_container;
4196                 ginst = klass->generic_class->context.class_inst;
4197         } else if (klass->generic_container && context_used) {
4198                 container = klass->generic_container;
4199                 ginst = container->context.class_inst;
4200         } else {
4201                 return FALSE;
4202         }
4203
4204         for (i = 0; i < container->type_argc; ++i) {
4205                 MonoType *type;
4206                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4207                         continue;
4208                 type = ginst->type_argv [i];
4209                 if (mini_type_is_reference (cfg, type))
4210                         return TRUE;
4211         }
4212         return FALSE;
4213 }
4214
4215 #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)
4216
4217 static MonoInst*
4218 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4219 {
4220         MonoMethod *mono_castclass;
4221         MonoInst *res;
4222
4223         mono_castclass = mono_marshal_get_castclass_with_cache ();
4224
4225         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4226         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4227         reset_cast_details (cfg);
4228         *out_bblock = cfg->cbb;
4229
4230         return res;
4231 }
4232
4233 static MonoInst*
4234 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4235 {
4236         MonoInst *args [3];
4237         int idx;
4238
4239         /* obj */
4240         args [0] = obj;
4241
4242         /* klass */
4243         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4244
4245         /* inline cache*/
4246         if (cfg->compile_aot) {
4247                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4248                 cfg->castclass_cache_index ++;
4249                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4250                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4251         } else {
4252                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4253         }
4254
4255         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4256
4257         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4258 }
4259
4260 /*
4261  * Returns NULL and set the cfg exception on error.
4262  */
4263 static MonoInst*
4264 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4265 {
4266         MonoBasicBlock *is_null_bb;
4267         int obj_reg = src->dreg;
4268         int vtable_reg = alloc_preg (cfg);
4269         int context_used;
4270         MonoInst *klass_inst = NULL, *res;
4271         MonoBasicBlock *bblock;
4272
4273         *out_bb = cfg->cbb;
4274
4275         context_used = mini_class_check_context_used (cfg, klass);
4276
4277         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4278                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4279                 (*inline_costs) += 2;
4280                 *out_bb = cfg->cbb;
4281                 return res;
4282         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4283                 MonoMethod *mono_castclass;
4284                 MonoInst *iargs [1];
4285                 int costs;
4286
4287                 mono_castclass = mono_marshal_get_castclass (klass); 
4288                 iargs [0] = src;
4289                                 
4290                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4291                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4292                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4293                 reset_cast_details (cfg);
4294                 CHECK_CFG_EXCEPTION;
4295                 g_assert (costs > 0);
4296                                 
4297                 cfg->real_offset += 5;
4298
4299                 (*inline_costs) += costs;
4300
4301                 *out_bb = cfg->cbb;
4302                 return src;
4303         }
4304
4305         if (context_used) {
4306                 MonoInst *args [3];
4307
4308                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4309                         MonoInst *cache_ins;
4310
4311                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4312
4313                         /* obj */
4314                         args [0] = src;
4315
4316                         /* klass - it's the second element of the cache entry*/
4317                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4318
4319                         /* cache */
4320                         args [2] = cache_ins;
4321
4322                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4323                 }
4324
4325                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4326         }
4327
4328         NEW_BBLOCK (cfg, is_null_bb);
4329
4330         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4331         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4332
4333         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4334
4335         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4336                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4337                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4338         } else {
4339                 int klass_reg = alloc_preg (cfg);
4340
4341                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4342
4343                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4344                         /* the remoting code is broken, access the class for now */
4345                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4346                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4347                                 if (!vt) {
4348                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4349                                         cfg->exception_ptr = klass;
4350                                         return NULL;
4351                                 }
4352                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4353                         } else {
4354                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4355                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4356                         }
4357                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4358                 } else {
4359                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4360                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4361                 }
4362         }
4363
4364         MONO_START_BB (cfg, is_null_bb);
4365
4366         reset_cast_details (cfg);
4367
4368         *out_bb = cfg->cbb;
4369
4370         return src;
4371
4372 exception_exit:
4373         return NULL;
4374 }
4375
4376 /*
4377  * Returns NULL and set the cfg exception on error.
4378  */
4379 static MonoInst*
4380 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4381 {
4382         MonoInst *ins;
4383         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4384         int obj_reg = src->dreg;
4385         int vtable_reg = alloc_preg (cfg);
4386         int res_reg = alloc_ireg_ref (cfg);
4387         MonoInst *klass_inst = NULL;
4388
4389         if (context_used) {
4390                 MonoInst *args [3];
4391
4392                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4393                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4394                         MonoInst *cache_ins;
4395
4396                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4397
4398                         /* obj */
4399                         args [0] = src;
4400
4401                         /* klass - it's the second element of the cache entry*/
4402                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4403
4404                         /* cache */
4405                         args [2] = cache_ins;
4406
4407                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4408                 }
4409
4410                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4411         }
4412
4413         NEW_BBLOCK (cfg, is_null_bb);
4414         NEW_BBLOCK (cfg, false_bb);
4415         NEW_BBLOCK (cfg, end_bb);
4416
4417         /* Do the assignment at the beginning, so the other assignment can be if converted */
4418         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4419         ins->type = STACK_OBJ;
4420         ins->klass = klass;
4421
4422         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4423         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4424
4425         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4426
4427         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4428                 g_assert (!context_used);
4429                 /* the is_null_bb target simply copies the input register to the output */
4430                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4431         } else {
4432                 int klass_reg = alloc_preg (cfg);
4433
4434                 if (klass->rank) {
4435                         int rank_reg = alloc_preg (cfg);
4436                         int eclass_reg = alloc_preg (cfg);
4437
4438                         g_assert (!context_used);
4439                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4440                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4441                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4442                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4443                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4444                         if (klass->cast_class == mono_defaults.object_class) {
4445                                 int parent_reg = alloc_preg (cfg);
4446                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4447                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4448                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4449                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4450                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4451                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4452                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4453                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4454                         } else if (klass->cast_class == mono_defaults.enum_class) {
4455                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4456                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4457                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4458                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4459                         } else {
4460                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4461                                         /* Check that the object is a vector too */
4462                                         int bounds_reg = alloc_preg (cfg);
4463                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4464                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4465                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4466                                 }
4467
4468                                 /* the is_null_bb target simply copies the input register to the output */
4469                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4470                         }
4471                 } else if (mono_class_is_nullable (klass)) {
4472                         g_assert (!context_used);
4473                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4474                         /* the is_null_bb target simply copies the input register to the output */
4475                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4476                 } else {
4477                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4478                                 g_assert (!context_used);
4479                                 /* the remoting code is broken, access the class for now */
4480                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4481                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4482                                         if (!vt) {
4483                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4484                                                 cfg->exception_ptr = klass;
4485                                                 return NULL;
4486                                         }
4487                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4488                                 } else {
4489                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4490                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4491                                 }
4492                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4493                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4494                         } else {
4495                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4496                                 /* the is_null_bb target simply copies the input register to the output */
4497                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4498                         }
4499                 }
4500         }
4501
4502         MONO_START_BB (cfg, false_bb);
4503
4504         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4505         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4506
4507         MONO_START_BB (cfg, is_null_bb);
4508
4509         MONO_START_BB (cfg, end_bb);
4510
4511         return ins;
4512 }
4513
4514 static MonoInst*
4515 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4516 {
4517         /* This opcode takes as input an object reference and a class, and returns:
4518         0) if the object is an instance of the class,
4519         1) if the object is not instance of the class,
4520         2) if the object is a proxy whose type cannot be determined */
4521
4522         MonoInst *ins;
4523 #ifndef DISABLE_REMOTING
4524         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4525 #else
4526         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4527 #endif
4528         int obj_reg = src->dreg;
4529         int dreg = alloc_ireg (cfg);
4530         int tmp_reg;
4531 #ifndef DISABLE_REMOTING
4532         int klass_reg = alloc_preg (cfg);
4533 #endif
4534
4535         NEW_BBLOCK (cfg, true_bb);
4536         NEW_BBLOCK (cfg, false_bb);
4537         NEW_BBLOCK (cfg, end_bb);
4538 #ifndef DISABLE_REMOTING
4539         NEW_BBLOCK (cfg, false2_bb);
4540         NEW_BBLOCK (cfg, no_proxy_bb);
4541 #endif
4542
4543         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4544         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4545
4546         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4547 #ifndef DISABLE_REMOTING
4548                 NEW_BBLOCK (cfg, interface_fail_bb);
4549 #endif
4550
4551                 tmp_reg = alloc_preg (cfg);
4552                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4553 #ifndef DISABLE_REMOTING
4554                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4555                 MONO_START_BB (cfg, interface_fail_bb);
4556                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4557                 
4558                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4559
4560                 tmp_reg = alloc_preg (cfg);
4561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4562                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4563                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4564 #else
4565                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4566 #endif
4567         } else {
4568 #ifndef DISABLE_REMOTING
4569                 tmp_reg = alloc_preg (cfg);
4570                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4571                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4572
4573                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4574                 tmp_reg = alloc_preg (cfg);
4575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4576                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4577
4578                 tmp_reg = alloc_preg (cfg);             
4579                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4580                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4581                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4582                 
4583                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4584                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4585
4586                 MONO_START_BB (cfg, no_proxy_bb);
4587
4588                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4589 #else
4590                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4591 #endif
4592         }
4593
4594         MONO_START_BB (cfg, false_bb);
4595
4596         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4597         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4598
4599 #ifndef DISABLE_REMOTING
4600         MONO_START_BB (cfg, false2_bb);
4601
4602         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4603         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4604 #endif
4605
4606         MONO_START_BB (cfg, true_bb);
4607
4608         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4609
4610         MONO_START_BB (cfg, end_bb);
4611
4612         /* FIXME: */
4613         MONO_INST_NEW (cfg, ins, OP_ICONST);
4614         ins->dreg = dreg;
4615         ins->type = STACK_I4;
4616
4617         return ins;
4618 }
4619
4620 static MonoInst*
4621 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4622 {
4623         /* This opcode takes as input an object reference and a class, and returns:
4624         0) if the object is an instance of the class,
4625         1) if the object is a proxy whose type cannot be determined
4626         an InvalidCastException exception is thrown otherwhise*/
4627         
4628         MonoInst *ins;
4629 #ifndef DISABLE_REMOTING
4630         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4631 #else
4632         MonoBasicBlock *ok_result_bb;
4633 #endif
4634         int obj_reg = src->dreg;
4635         int dreg = alloc_ireg (cfg);
4636         int tmp_reg = alloc_preg (cfg);
4637
4638 #ifndef DISABLE_REMOTING
4639         int klass_reg = alloc_preg (cfg);
4640         NEW_BBLOCK (cfg, end_bb);
4641 #endif
4642
4643         NEW_BBLOCK (cfg, ok_result_bb);
4644
4645         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4646         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4647
4648         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4649
4650         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4651 #ifndef DISABLE_REMOTING
4652                 NEW_BBLOCK (cfg, interface_fail_bb);
4653         
4654                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4655                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4656                 MONO_START_BB (cfg, interface_fail_bb);
4657                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4658
4659                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4660
4661                 tmp_reg = alloc_preg (cfg);             
4662                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4663                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4664                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4665                 
4666                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4667                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4668 #else
4669                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4670                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4671                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4672 #endif
4673         } else {
4674 #ifndef DISABLE_REMOTING
4675                 NEW_BBLOCK (cfg, no_proxy_bb);
4676
4677                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4678                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4679                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4680
4681                 tmp_reg = alloc_preg (cfg);
4682                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4683                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4684
4685                 tmp_reg = alloc_preg (cfg);
4686                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4687                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4688                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4689
4690                 NEW_BBLOCK (cfg, fail_1_bb);
4691                 
4692                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4693
4694                 MONO_START_BB (cfg, fail_1_bb);
4695
4696                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4697                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4698
4699                 MONO_START_BB (cfg, no_proxy_bb);
4700
4701                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4702 #else
4703                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4704 #endif
4705         }
4706
4707         MONO_START_BB (cfg, ok_result_bb);
4708
4709         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4710
4711 #ifndef DISABLE_REMOTING
4712         MONO_START_BB (cfg, end_bb);
4713 #endif
4714
4715         /* FIXME: */
4716         MONO_INST_NEW (cfg, ins, OP_ICONST);
4717         ins->dreg = dreg;
4718         ins->type = STACK_I4;
4719
4720         return ins;
4721 }
4722
4723 static G_GNUC_UNUSED MonoInst*
4724 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4725 {
4726         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4727         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4728         gboolean is_i4 = TRUE;
4729
4730         switch (enum_type->type) {
4731         case MONO_TYPE_I8:
4732         case MONO_TYPE_U8:
4733 #if SIZEOF_REGISTER == 8
4734         case MONO_TYPE_I:
4735         case MONO_TYPE_U:
4736 #endif
4737                 is_i4 = FALSE;
4738                 break;
4739         }
4740
4741         {
4742                 MonoInst *load, *and, *cmp, *ceq;
4743                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4744                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4745                 int dest_reg = alloc_ireg (cfg);
4746
4747                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4748                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4749                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4750                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4751
4752                 ceq->type = STACK_I4;
4753
4754                 if (!is_i4) {
4755                         load = mono_decompose_opcode (cfg, load, NULL);
4756                         and = mono_decompose_opcode (cfg, and, NULL);
4757                         cmp = mono_decompose_opcode (cfg, cmp, NULL);
4758                         ceq = mono_decompose_opcode (cfg, ceq, NULL);
4759                 }
4760
4761                 return ceq;
4762         }
4763 }
4764
4765 /*
4766  * Returns NULL and set the cfg exception on error.
4767  */
4768 static G_GNUC_UNUSED MonoInst*
4769 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4770 {
4771         MonoInst *ptr;
4772         int dreg;
4773         gpointer trampoline;
4774         MonoInst *obj, *method_ins, *tramp_ins;
4775         MonoDomain *domain;
4776         guint8 **code_slot;
4777         
4778         // FIXME reenable optimisation for virtual case
4779         if (virtual)
4780                 return NULL;
4781
4782         if (virtual) {
4783                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4784                 g_assert (invoke);
4785
4786                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4787                         return NULL;
4788         }
4789
4790         obj = handle_alloc (cfg, klass, FALSE, 0);
4791         if (!obj)
4792                 return NULL;
4793
4794         /* Inline the contents of mono_delegate_ctor */
4795
4796         /* Set target field */
4797         /* Optimize away setting of NULL target */
4798         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4799                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4800                 if (cfg->gen_write_barriers) {
4801                         dreg = alloc_preg (cfg);
4802                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4803                         emit_write_barrier (cfg, ptr, target);
4804                 }
4805         }
4806
4807         /* Set method field */
4808         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4809         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4810
4811         /* 
4812          * To avoid looking up the compiled code belonging to the target method
4813          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4814          * store it, and we fill it after the method has been compiled.
4815          */
4816         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4817                 MonoInst *code_slot_ins;
4818
4819                 if (context_used) {
4820                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4821                 } else {
4822                         domain = mono_domain_get ();
4823                         mono_domain_lock (domain);
4824                         if (!domain_jit_info (domain)->method_code_hash)
4825                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4826                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4827                         if (!code_slot) {
4828                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4829                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4830                         }
4831                         mono_domain_unlock (domain);
4832
4833                         if (cfg->compile_aot)
4834                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4835                         else
4836                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4837                 }
4838                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4839         }
4840
4841         if (cfg->compile_aot) {
4842                 MonoDelegateClassMethodPair *del_tramp;
4843
4844                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4845                 del_tramp->klass = klass;
4846                 del_tramp->method = context_used ? NULL : method;
4847                 del_tramp->virtual = virtual;
4848                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4849         } else {
4850                 if (virtual)
4851                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4852                 else
4853                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4854                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4855         }
4856
4857         /* Set invoke_impl field */
4858         if (virtual) {
4859                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4860         } else {
4861                 dreg = alloc_preg (cfg);
4862                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4863                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4864
4865                 dreg = alloc_preg (cfg);
4866                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4867                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4868         }
4869
4870         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4871
4872         return obj;
4873 }
4874
4875 static MonoInst*
4876 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4877 {
4878         MonoJitICallInfo *info;
4879
4880         /* Need to register the icall so it gets an icall wrapper */
4881         info = mono_get_array_new_va_icall (rank);
4882
4883         cfg->flags |= MONO_CFG_HAS_VARARGS;
4884
4885         /* mono_array_new_va () needs a vararg calling convention */
4886         cfg->disable_llvm = TRUE;
4887
4888         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4889         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4890 }
4891
4892 /*
4893  * handle_constrained_gsharedvt_call:
4894  *
4895  *   Handle constrained calls where the receiver is a gsharedvt type.
4896  * Return the instruction representing the call. Set the cfg exception on failure.
4897  */
4898 static MonoInst*
4899 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
4900                                                                    gboolean *ref_emit_widen, MonoBasicBlock **ref_bblock)
4901 {
4902         MonoInst *ins = NULL;
4903         MonoBasicBlock *bblock = *ref_bblock;
4904         gboolean emit_widen = *ref_emit_widen;
4905
4906         /*
4907          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
4908          * 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
4909          * pack the arguments into an array, and do the rest of the work in in an icall.
4910          */
4911         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
4912                 (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)) &&
4913                 (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]))))) {
4914                 MonoInst *args [16];
4915
4916                 /*
4917                  * This case handles calls to
4918                  * - object:ToString()/Equals()/GetHashCode(),
4919                  * - System.IComparable<T>:CompareTo()
4920                  * - System.IEquatable<T>:Equals ()
4921                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
4922                  */
4923
4924                 args [0] = sp [0];
4925                 if (mono_method_check_context_used (cmethod))
4926                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
4927                 else
4928                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
4929                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
4930
4931                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
4932                 if (fsig->hasthis && fsig->param_count) {
4933                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
4934                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
4935                         ins->dreg = alloc_preg (cfg);
4936                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
4937                         MONO_ADD_INS (cfg->cbb, ins);
4938                         args [4] = ins;
4939
4940                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
4941                                 int addr_reg;
4942
4943                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4944
4945                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
4946                                 addr_reg = ins->dreg;
4947                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
4948                         } else {
4949                                 EMIT_NEW_ICONST (cfg, args [3], 0);
4950                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
4951                         }
4952                 } else {
4953                         EMIT_NEW_ICONST (cfg, args [3], 0);
4954                         EMIT_NEW_ICONST (cfg, args [4], 0);
4955                 }
4956                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
4957                 emit_widen = FALSE;
4958
4959                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
4960                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
4961                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
4962                         MonoInst *add;
4963
4964                         /* Unbox */
4965                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
4966                         MONO_ADD_INS (cfg->cbb, add);
4967                         /* Load value */
4968                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
4969                         MONO_ADD_INS (cfg->cbb, ins);
4970                         /* ins represents the call result */
4971                 }
4972         } else {
4973                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
4974         }
4975
4976         *ref_emit_widen = emit_widen;
4977         *ref_bblock = bblock;
4978
4979         return ins;
4980
4981  exception_exit:
4982         return NULL;
4983 }
4984
4985 static void
4986 mono_emit_load_got_addr (MonoCompile *cfg)
4987 {
4988         MonoInst *getaddr, *dummy_use;
4989
4990         if (!cfg->got_var || cfg->got_var_allocated)
4991                 return;
4992
4993         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4994         getaddr->cil_code = cfg->header->code;
4995         getaddr->dreg = cfg->got_var->dreg;
4996
4997         /* Add it to the start of the first bblock */
4998         if (cfg->bb_entry->code) {
4999                 getaddr->next = cfg->bb_entry->code;
5000                 cfg->bb_entry->code = getaddr;
5001         }
5002         else
5003                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5004
5005         cfg->got_var_allocated = TRUE;
5006
5007         /* 
5008          * Add a dummy use to keep the got_var alive, since real uses might
5009          * only be generated by the back ends.
5010          * Add it to end_bblock, so the variable's lifetime covers the whole
5011          * method.
5012          * It would be better to make the usage of the got var explicit in all
5013          * cases when the backend needs it (i.e. calls, throw etc.), so this
5014          * wouldn't be needed.
5015          */
5016         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5017         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5018 }
5019
5020 static int inline_limit;
5021 static gboolean inline_limit_inited;
5022
5023 static gboolean
5024 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5025 {
5026         MonoMethodHeaderSummary header;
5027         MonoVTable *vtable;
5028 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5029         MonoMethodSignature *sig = mono_method_signature (method);
5030         int i;
5031 #endif
5032
5033         if (cfg->disable_inline)
5034                 return FALSE;
5035         if (cfg->generic_sharing_context)
5036                 return FALSE;
5037
5038         if (cfg->inline_depth > 10)
5039                 return FALSE;
5040
5041 #ifdef MONO_ARCH_HAVE_LMF_OPS
5042         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
5043                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
5044             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
5045                 return TRUE;
5046 #endif
5047
5048
5049         if (!mono_method_get_header_summary (method, &header))
5050                 return FALSE;
5051
5052         /*runtime, icall and pinvoke are checked by summary call*/
5053         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5054             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5055             (mono_class_is_marshalbyref (method->klass)) ||
5056             header.has_clauses)
5057                 return FALSE;
5058
5059         /* also consider num_locals? */
5060         /* Do the size check early to avoid creating vtables */
5061         if (!inline_limit_inited) {
5062                 if (g_getenv ("MONO_INLINELIMIT"))
5063                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5064                 else
5065                         inline_limit = INLINE_LENGTH_LIMIT;
5066                 inline_limit_inited = TRUE;
5067         }
5068         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5069                 return FALSE;
5070
5071         /*
5072          * if we can initialize the class of the method right away, we do,
5073          * otherwise we don't allow inlining if the class needs initialization,
5074          * since it would mean inserting a call to mono_runtime_class_init()
5075          * inside the inlined code
5076          */
5077         if (!(cfg->opt & MONO_OPT_SHARED)) {
5078                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5079                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5080                         vtable = mono_class_vtable (cfg->domain, method->klass);
5081                         if (!vtable)
5082                                 return FALSE;
5083                         if (!cfg->compile_aot)
5084                                 mono_runtime_class_init (vtable);
5085                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5086                         if (cfg->run_cctors && method->klass->has_cctor) {
5087                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5088                                 if (!method->klass->runtime_info)
5089                                         /* No vtable created yet */
5090                                         return FALSE;
5091                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5092                                 if (!vtable)
5093                                         return FALSE;
5094                                 /* This makes so that inline cannot trigger */
5095                                 /* .cctors: too many apps depend on them */
5096                                 /* running with a specific order... */
5097                                 if (! vtable->initialized)
5098                                         return FALSE;
5099                                 mono_runtime_class_init (vtable);
5100                         }
5101                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5102                         if (!method->klass->runtime_info)
5103                                 /* No vtable created yet */
5104                                 return FALSE;
5105                         vtable = mono_class_vtable (cfg->domain, method->klass);
5106                         if (!vtable)
5107                                 return FALSE;
5108                         if (!vtable->initialized)
5109                                 return FALSE;
5110                 }
5111         } else {
5112                 /* 
5113                  * If we're compiling for shared code
5114                  * the cctor will need to be run at aot method load time, for example,
5115                  * or at the end of the compilation of the inlining method.
5116                  */
5117                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5118                         return FALSE;
5119         }
5120
5121         /*
5122          * CAS - do not inline methods with declarative security
5123          * Note: this has to be before any possible return TRUE;
5124          */
5125         if (mono_security_method_has_declsec (method))
5126                 return FALSE;
5127
5128 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5129         if (mono_arch_is_soft_float ()) {
5130                 /* FIXME: */
5131                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5132                         return FALSE;
5133                 for (i = 0; i < sig->param_count; ++i)
5134                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5135                                 return FALSE;
5136         }
5137 #endif
5138
5139         if (g_list_find (cfg->dont_inline, method))
5140                 return FALSE;
5141
5142         return TRUE;
5143 }
5144
5145 static gboolean
5146 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5147 {
5148         if (!cfg->compile_aot) {
5149                 g_assert (vtable);
5150                 if (vtable->initialized)
5151                         return FALSE;
5152         }
5153
5154         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5155                 if (cfg->method == method)
5156                         return FALSE;
5157         }
5158
5159         if (!mono_class_needs_cctor_run (klass, method))
5160                 return FALSE;
5161
5162         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5163                 /* The initialization is already done before the method is called */
5164                 return FALSE;
5165
5166         return TRUE;
5167 }
5168
5169 static MonoInst*
5170 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5171 {
5172         MonoInst *ins;
5173         guint32 size;
5174         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5175         int context_used;
5176
5177         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5178                 size = -1;
5179         } else {
5180                 mono_class_init (klass);
5181                 size = mono_class_array_element_size (klass);
5182         }
5183
5184         mult_reg = alloc_preg (cfg);
5185         array_reg = arr->dreg;
5186         index_reg = index->dreg;
5187
5188 #if SIZEOF_REGISTER == 8
5189         /* The array reg is 64 bits but the index reg is only 32 */
5190         if (COMPILE_LLVM (cfg)) {
5191                 /* Not needed */
5192                 index2_reg = index_reg;
5193         } else {
5194                 index2_reg = alloc_preg (cfg);
5195                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5196         }
5197 #else
5198         if (index->type == STACK_I8) {
5199                 index2_reg = alloc_preg (cfg);
5200                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5201         } else {
5202                 index2_reg = index_reg;
5203         }
5204 #endif
5205
5206         if (bcheck)
5207                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5208
5209 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5210         if (size == 1 || size == 2 || size == 4 || size == 8) {
5211                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5212
5213                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5214                 ins->klass = mono_class_get_element_class (klass);
5215                 ins->type = STACK_MP;
5216
5217                 return ins;
5218         }
5219 #endif          
5220
5221         add_reg = alloc_ireg_mp (cfg);
5222
5223         if (size == -1) {
5224                 MonoInst *rgctx_ins;
5225
5226                 /* gsharedvt */
5227                 g_assert (cfg->generic_sharing_context);
5228                 context_used = mini_class_check_context_used (cfg, klass);
5229                 g_assert (context_used);
5230                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5231                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5232         } else {
5233                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5234         }
5235         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5236         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5237         ins->klass = mono_class_get_element_class (klass);
5238         ins->type = STACK_MP;
5239         MONO_ADD_INS (cfg->cbb, ins);
5240
5241         return ins;
5242 }
5243
5244 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5245 static MonoInst*
5246 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5247 {
5248         int bounds_reg = alloc_preg (cfg);
5249         int add_reg = alloc_ireg_mp (cfg);
5250         int mult_reg = alloc_preg (cfg);
5251         int mult2_reg = alloc_preg (cfg);
5252         int low1_reg = alloc_preg (cfg);
5253         int low2_reg = alloc_preg (cfg);
5254         int high1_reg = alloc_preg (cfg);
5255         int high2_reg = alloc_preg (cfg);
5256         int realidx1_reg = alloc_preg (cfg);
5257         int realidx2_reg = alloc_preg (cfg);
5258         int sum_reg = alloc_preg (cfg);
5259         int index1, index2, tmpreg;
5260         MonoInst *ins;
5261         guint32 size;
5262
5263         mono_class_init (klass);
5264         size = mono_class_array_element_size (klass);
5265
5266         index1 = index_ins1->dreg;
5267         index2 = index_ins2->dreg;
5268
5269 #if SIZEOF_REGISTER == 8
5270         /* The array reg is 64 bits but the index reg is only 32 */
5271         if (COMPILE_LLVM (cfg)) {
5272                 /* Not needed */
5273         } else {
5274                 tmpreg = alloc_preg (cfg);
5275                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5276                 index1 = tmpreg;
5277                 tmpreg = alloc_preg (cfg);
5278                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5279                 index2 = tmpreg;
5280         }
5281 #else
5282         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5283         tmpreg = -1;
5284 #endif
5285
5286         /* range checking */
5287         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5288                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5289
5290         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5291                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5292         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5293         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5294                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5295         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5296         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5297
5298         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5299                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5300         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5301         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5302                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5303         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5304         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5305
5306         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5307         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5308         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5309         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5310         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5311
5312         ins->type = STACK_MP;
5313         ins->klass = klass;
5314         MONO_ADD_INS (cfg->cbb, ins);
5315
5316         return ins;
5317 }
5318 #endif
5319
5320 static MonoInst*
5321 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5322 {
5323         int rank;
5324         MonoInst *addr;
5325         MonoMethod *addr_method;
5326         int element_size;
5327         MonoClass *eclass = cmethod->klass->element_class;
5328
5329         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5330
5331         if (rank == 1)
5332                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5333
5334 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5335         /* emit_ldelema_2 depends on OP_LMUL */
5336         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (cfg, eclass)) {
5337                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5338         }
5339 #endif
5340
5341         if (mini_is_gsharedvt_variable_klass (cfg, eclass))
5342                 element_size = 0;
5343         else
5344                 element_size = mono_class_array_element_size (eclass);
5345         addr_method = mono_marshal_get_array_address (rank, element_size);
5346         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5347
5348         return addr;
5349 }
5350
5351 static MonoBreakPolicy
5352 always_insert_breakpoint (MonoMethod *method)
5353 {
5354         return MONO_BREAK_POLICY_ALWAYS;
5355 }
5356
5357 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5358
5359 /**
5360  * mono_set_break_policy:
5361  * policy_callback: the new callback function
5362  *
5363  * Allow embedders to decide wherther to actually obey breakpoint instructions
5364  * (both break IL instructions and Debugger.Break () method calls), for example
5365  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5366  * untrusted or semi-trusted code.
5367  *
5368  * @policy_callback will be called every time a break point instruction needs to
5369  * be inserted with the method argument being the method that calls Debugger.Break()
5370  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5371  * if it wants the breakpoint to not be effective in the given method.
5372  * #MONO_BREAK_POLICY_ALWAYS is the default.
5373  */
5374 void
5375 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5376 {
5377         if (policy_callback)
5378                 break_policy_func = policy_callback;
5379         else
5380                 break_policy_func = always_insert_breakpoint;
5381 }
5382
5383 static gboolean
5384 should_insert_brekpoint (MonoMethod *method) {
5385         switch (break_policy_func (method)) {
5386         case MONO_BREAK_POLICY_ALWAYS:
5387                 return TRUE;
5388         case MONO_BREAK_POLICY_NEVER:
5389                 return FALSE;
5390         case MONO_BREAK_POLICY_ON_DBG:
5391                 g_warning ("mdb no longer supported");
5392                 return FALSE;
5393         default:
5394                 g_warning ("Incorrect value returned from break policy callback");
5395                 return FALSE;
5396         }
5397 }
5398
5399 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5400 static MonoInst*
5401 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5402 {
5403         MonoInst *addr, *store, *load;
5404         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5405
5406         /* the bounds check is already done by the callers */
5407         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5408         if (is_set) {
5409                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5410                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5411                 if (mini_type_is_reference (cfg, fsig->params [2]))
5412                         emit_write_barrier (cfg, addr, load);
5413         } else {
5414                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5415                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5416         }
5417         return store;
5418 }
5419
5420
5421 static gboolean
5422 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5423 {
5424         return mini_type_is_reference (cfg, &klass->byval_arg);
5425 }
5426
5427 static MonoInst*
5428 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5429 {
5430         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5431                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5432                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5433                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5434                 MonoInst *iargs [3];
5435
5436                 if (!helper->slot)
5437                         mono_class_setup_vtable (obj_array);
5438                 g_assert (helper->slot);
5439
5440                 if (sp [0]->type != STACK_OBJ)
5441                         return NULL;
5442                 if (sp [2]->type != STACK_OBJ)
5443                         return NULL;
5444
5445                 iargs [2] = sp [2];
5446                 iargs [1] = sp [1];
5447                 iargs [0] = sp [0];
5448
5449                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5450         } else {
5451                 MonoInst *ins;
5452
5453                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5454                         MonoInst *addr;
5455
5456                         // FIXME-VT: OP_ICONST optimization
5457                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5458                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5459                         ins->opcode = OP_STOREV_MEMBASE;
5460                 } else if (sp [1]->opcode == OP_ICONST) {
5461                         int array_reg = sp [0]->dreg;
5462                         int index_reg = sp [1]->dreg;
5463                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5464
5465                         if (safety_checks)
5466                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5467                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5468                 } else {
5469                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5470                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5471                         if (generic_class_is_reference_type (cfg, klass))
5472                                 emit_write_barrier (cfg, addr, sp [2]);
5473                 }
5474                 return ins;
5475         }
5476 }
5477
5478 static MonoInst*
5479 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5480 {
5481         MonoClass *eklass;
5482         
5483         if (is_set)
5484                 eklass = mono_class_from_mono_type (fsig->params [2]);
5485         else
5486                 eklass = mono_class_from_mono_type (fsig->ret);
5487
5488         if (is_set) {
5489                 return emit_array_store (cfg, eklass, args, FALSE);
5490         } else {
5491                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5492                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5493                 return ins;
5494         }
5495 }
5496
5497 static gboolean
5498 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5499 {
5500         uint32_t align;
5501
5502         //Only allow for valuetypes
5503         if (!param_klass->valuetype || !return_klass->valuetype)
5504                 return FALSE;
5505
5506         //That are blitable
5507         if (param_klass->has_references || return_klass->has_references)
5508                 return FALSE;
5509
5510         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5511         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5512                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5513                 return FALSE;
5514
5515         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5516                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5517                 return FALSE;
5518
5519         //And have the same size
5520         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5521                 return FALSE;
5522         return TRUE;
5523 }
5524
5525 static MonoInst*
5526 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5527 {
5528         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5529         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5530
5531         //Valuetypes that are semantically equivalent
5532         if (is_unsafe_mov_compatible (param_klass, return_klass))
5533                 return args [0];
5534
5535         //Arrays of valuetypes that are semantically equivalent
5536         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5537                 return args [0];
5538
5539         return NULL;
5540 }
5541
5542 static MonoInst*
5543 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5544 {
5545 #ifdef MONO_ARCH_SIMD_INTRINSICS
5546         MonoInst *ins = NULL;
5547
5548         if (cfg->opt & MONO_OPT_SIMD) {
5549                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5550                 if (ins)
5551                         return ins;
5552         }
5553 #endif
5554
5555         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5556 }
5557
5558 static MonoInst*
5559 emit_memory_barrier (MonoCompile *cfg, int kind)
5560 {
5561         MonoInst *ins = NULL;
5562         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5563         MONO_ADD_INS (cfg->cbb, ins);
5564         ins->backend.memory_barrier_kind = kind;
5565
5566         return ins;
5567 }
5568
5569 static MonoInst*
5570 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5571 {
5572         MonoInst *ins = NULL;
5573         int opcode = 0;
5574
5575         /* The LLVM backend supports these intrinsics */
5576         if (cmethod->klass == mono_defaults.math_class) {
5577                 if (strcmp (cmethod->name, "Sin") == 0) {
5578                         opcode = OP_SIN;
5579                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5580                         opcode = OP_COS;
5581                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5582                         opcode = OP_SQRT;
5583                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5584                         opcode = OP_ABS;
5585                 }
5586
5587                 if (opcode && fsig->param_count == 1) {
5588                         MONO_INST_NEW (cfg, ins, opcode);
5589                         ins->type = STACK_R8;
5590                         ins->dreg = mono_alloc_freg (cfg);
5591                         ins->sreg1 = args [0]->dreg;
5592                         MONO_ADD_INS (cfg->cbb, ins);
5593                 }
5594
5595                 opcode = 0;
5596                 if (cfg->opt & MONO_OPT_CMOV) {
5597                         if (strcmp (cmethod->name, "Min") == 0) {
5598                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5599                                         opcode = OP_IMIN;
5600                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5601                                         opcode = OP_IMIN_UN;
5602                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5603                                         opcode = OP_LMIN;
5604                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5605                                         opcode = OP_LMIN_UN;
5606                         } else if (strcmp (cmethod->name, "Max") == 0) {
5607                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5608                                         opcode = OP_IMAX;
5609                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5610                                         opcode = OP_IMAX_UN;
5611                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5612                                         opcode = OP_LMAX;
5613                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5614                                         opcode = OP_LMAX_UN;
5615                         }
5616                 }
5617
5618                 if (opcode && fsig->param_count == 2) {
5619                         MONO_INST_NEW (cfg, ins, opcode);
5620                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5621                         ins->dreg = mono_alloc_ireg (cfg);
5622                         ins->sreg1 = args [0]->dreg;
5623                         ins->sreg2 = args [1]->dreg;
5624                         MONO_ADD_INS (cfg->cbb, ins);
5625                 }
5626         }
5627
5628         return ins;
5629 }
5630
5631 static MonoInst*
5632 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5633 {
5634         if (cmethod->klass == mono_defaults.array_class) {
5635                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5636                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5637                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5638                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5639                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5640                         return emit_array_unsafe_mov (cfg, fsig, args);
5641         }
5642
5643         return NULL;
5644 }
5645
5646 static MonoInst*
5647 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5648 {
5649         MonoInst *ins = NULL;
5650         
5651         static MonoClass *runtime_helpers_class = NULL;
5652         if (! runtime_helpers_class)
5653                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5654                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5655
5656         if (cmethod->klass == mono_defaults.string_class) {
5657                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5658                         int dreg = alloc_ireg (cfg);
5659                         int index_reg = alloc_preg (cfg);
5660                         int mult_reg = alloc_preg (cfg);
5661                         int add_reg = alloc_preg (cfg);
5662
5663 #if SIZEOF_REGISTER == 8
5664                         /* The array reg is 64 bits but the index reg is only 32 */
5665                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5666 #else
5667                         index_reg = args [1]->dreg;
5668 #endif  
5669                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5670
5671 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5672                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5673                         add_reg = ins->dreg;
5674                         /* Avoid a warning */
5675                         mult_reg = 0;
5676                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5677                                                                    add_reg, 0);
5678 #else
5679                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5680                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5681                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5682                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5683 #endif
5684                         type_from_op (cfg, ins, NULL, NULL);
5685                         return ins;
5686                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5687                         int dreg = alloc_ireg (cfg);
5688                         /* Decompose later to allow more optimizations */
5689                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5690                         ins->type = STACK_I4;
5691                         ins->flags |= MONO_INST_FAULT;
5692                         cfg->cbb->has_array_access = TRUE;
5693                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5694
5695                         return ins;
5696                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5697                         int mult_reg = alloc_preg (cfg);
5698                         int add_reg = alloc_preg (cfg);
5699
5700                         /* The corlib functions check for oob already. */
5701                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5702                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5703                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5704                         return cfg->cbb->last_ins;
5705                 } else 
5706                         return NULL;
5707         } else if (cmethod->klass == mono_defaults.object_class) {
5708
5709                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5710                         int dreg = alloc_ireg_ref (cfg);
5711                         int vt_reg = alloc_preg (cfg);
5712                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5713                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5714                         type_from_op (cfg, ins, NULL, NULL);
5715
5716                         return ins;
5717 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5718                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5719                         int dreg = alloc_ireg (cfg);
5720                         int t1 = alloc_ireg (cfg);
5721         
5722                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5723                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5724                         ins->type = STACK_I4;
5725
5726                         return ins;
5727 #endif
5728                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5729                         MONO_INST_NEW (cfg, ins, OP_NOP);
5730                         MONO_ADD_INS (cfg->cbb, ins);
5731                         return ins;
5732                 } else
5733                         return NULL;
5734         } else if (cmethod->klass == mono_defaults.array_class) {
5735                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5736                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5737                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5738                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5739
5740 #ifndef MONO_BIG_ARRAYS
5741                 /*
5742                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5743                  * Array methods.
5744                  */
5745                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5746                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5747                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5748                         int dreg = alloc_ireg (cfg);
5749                         int bounds_reg = alloc_ireg_mp (cfg);
5750                         MonoBasicBlock *end_bb, *szarray_bb;
5751                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5752
5753                         NEW_BBLOCK (cfg, end_bb);
5754                         NEW_BBLOCK (cfg, szarray_bb);
5755
5756                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5757                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5758                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5759                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5760                         /* Non-szarray case */
5761                         if (get_length)
5762                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5763                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5764                         else
5765                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5766                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5767                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5768                         MONO_START_BB (cfg, szarray_bb);
5769                         /* Szarray case */
5770                         if (get_length)
5771                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5772                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5773                         else
5774                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5775                         MONO_START_BB (cfg, end_bb);
5776
5777                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5778                         ins->type = STACK_I4;
5779                         
5780                         return ins;
5781                 }
5782 #endif
5783
5784                 if (cmethod->name [0] != 'g')
5785                         return NULL;
5786
5787                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5788                         int dreg = alloc_ireg (cfg);
5789                         int vtable_reg = alloc_preg (cfg);
5790                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5791                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5792                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5793                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5794                         type_from_op (cfg, ins, NULL, NULL);
5795
5796                         return ins;
5797                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5798                         int dreg = alloc_ireg (cfg);
5799
5800                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5801                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5802                         type_from_op (cfg, ins, NULL, NULL);
5803
5804                         return ins;
5805                 } else
5806                         return NULL;
5807         } else if (cmethod->klass == runtime_helpers_class) {
5808
5809                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5810                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5811                         return ins;
5812                 } else
5813                         return NULL;
5814         } else if (cmethod->klass == mono_defaults.thread_class) {
5815                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5816                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5817                         MONO_ADD_INS (cfg->cbb, ins);
5818                         return ins;
5819                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5820                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5821                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5822                         guint32 opcode = 0;
5823                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5824
5825                         if (fsig->params [0]->type == MONO_TYPE_I1)
5826                                 opcode = OP_LOADI1_MEMBASE;
5827                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5828                                 opcode = OP_LOADU1_MEMBASE;
5829                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5830                                 opcode = OP_LOADI2_MEMBASE;
5831                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5832                                 opcode = OP_LOADU2_MEMBASE;
5833                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5834                                 opcode = OP_LOADI4_MEMBASE;
5835                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5836                                 opcode = OP_LOADU4_MEMBASE;
5837                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5838                                 opcode = OP_LOADI8_MEMBASE;
5839                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5840                                 opcode = OP_LOADR4_MEMBASE;
5841                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5842                                 opcode = OP_LOADR8_MEMBASE;
5843                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5844                                 opcode = OP_LOAD_MEMBASE;
5845
5846                         if (opcode) {
5847                                 MONO_INST_NEW (cfg, ins, opcode);
5848                                 ins->inst_basereg = args [0]->dreg;
5849                                 ins->inst_offset = 0;
5850                                 MONO_ADD_INS (cfg->cbb, ins);
5851
5852                                 switch (fsig->params [0]->type) {
5853                                 case MONO_TYPE_I1:
5854                                 case MONO_TYPE_U1:
5855                                 case MONO_TYPE_I2:
5856                                 case MONO_TYPE_U2:
5857                                 case MONO_TYPE_I4:
5858                                 case MONO_TYPE_U4:
5859                                         ins->dreg = mono_alloc_ireg (cfg);
5860                                         ins->type = STACK_I4;
5861                                         break;
5862                                 case MONO_TYPE_I8:
5863                                 case MONO_TYPE_U8:
5864                                         ins->dreg = mono_alloc_lreg (cfg);
5865                                         ins->type = STACK_I8;
5866                                         break;
5867                                 case MONO_TYPE_I:
5868                                 case MONO_TYPE_U:
5869                                         ins->dreg = mono_alloc_ireg (cfg);
5870 #if SIZEOF_REGISTER == 8
5871                                         ins->type = STACK_I8;
5872 #else
5873                                         ins->type = STACK_I4;
5874 #endif
5875                                         break;
5876                                 case MONO_TYPE_R4:
5877                                 case MONO_TYPE_R8:
5878                                         ins->dreg = mono_alloc_freg (cfg);
5879                                         ins->type = STACK_R8;
5880                                         break;
5881                                 default:
5882                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5883                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5884                                         ins->type = STACK_OBJ;
5885                                         break;
5886                                 }
5887
5888                                 if (opcode == OP_LOADI8_MEMBASE)
5889                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5890
5891                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5892
5893                                 return ins;
5894                         }
5895                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5896                         guint32 opcode = 0;
5897                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5898
5899                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5900                                 opcode = OP_STOREI1_MEMBASE_REG;
5901                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5902                                 opcode = OP_STOREI2_MEMBASE_REG;
5903                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5904                                 opcode = OP_STOREI4_MEMBASE_REG;
5905                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5906                                 opcode = OP_STOREI8_MEMBASE_REG;
5907                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5908                                 opcode = OP_STORER4_MEMBASE_REG;
5909                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5910                                 opcode = OP_STORER8_MEMBASE_REG;
5911                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5912                                 opcode = OP_STORE_MEMBASE_REG;
5913
5914                         if (opcode) {
5915                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5916
5917                                 MONO_INST_NEW (cfg, ins, opcode);
5918                                 ins->sreg1 = args [1]->dreg;
5919                                 ins->inst_destbasereg = args [0]->dreg;
5920                                 ins->inst_offset = 0;
5921                                 MONO_ADD_INS (cfg->cbb, ins);
5922
5923                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5924                                         ins = mono_decompose_opcode (cfg, ins, NULL);
5925
5926                                 return ins;
5927                         }
5928                 }
5929         } else if (cmethod->klass == mono_defaults.monitor_class) {
5930 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5931                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5932                         MonoCallInst *call;
5933
5934                         if (COMPILE_LLVM (cfg)) {
5935                                 /* 
5936                                  * Pass the argument normally, the LLVM backend will handle the
5937                                  * calling convention problems.
5938                                  */
5939                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5940                         } else {
5941                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5942                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5943                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5944                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5945                         }
5946
5947                         return (MonoInst*)call;
5948 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5949                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5950                         MonoCallInst *call;
5951
5952                         if (COMPILE_LLVM (cfg)) {
5953                                 /*
5954                                  * Pass the argument normally, the LLVM backend will handle the
5955                                  * calling convention problems.
5956                                  */
5957                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5958                         } else {
5959                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5960                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5961                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5962                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5963                         }
5964
5965                         return (MonoInst*)call;
5966 #endif
5967                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
5968                         MonoCallInst *call;
5969
5970                         if (COMPILE_LLVM (cfg)) {
5971                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5972                         } else {
5973                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5974                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5975                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5976                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5977                         }
5978
5979                         return (MonoInst*)call;
5980                 }
5981 #endif
5982         } else if (cmethod->klass->image == mono_defaults.corlib &&
5983                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5984                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5985                 ins = NULL;
5986
5987 #if SIZEOF_REGISTER == 8
5988                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5989                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5990                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5991                                 ins->dreg = mono_alloc_preg (cfg);
5992                                 ins->sreg1 = args [0]->dreg;
5993                                 ins->type = STACK_I8;
5994                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5995                                 MONO_ADD_INS (cfg->cbb, ins);
5996                         } else {
5997                                 MonoInst *load_ins;
5998
5999                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6000
6001                                 /* 64 bit reads are already atomic */
6002                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6003                                 load_ins->dreg = mono_alloc_preg (cfg);
6004                                 load_ins->inst_basereg = args [0]->dreg;
6005                                 load_ins->inst_offset = 0;
6006                                 load_ins->type = STACK_I8;
6007                                 MONO_ADD_INS (cfg->cbb, load_ins);
6008
6009                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6010
6011                                 ins = load_ins;
6012                         }
6013                 }
6014 #endif
6015
6016                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6017                         MonoInst *ins_iconst;
6018                         guint32 opcode = 0;
6019
6020                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6021                                 opcode = OP_ATOMIC_ADD_I4;
6022                                 cfg->has_atomic_add_i4 = TRUE;
6023                         }
6024 #if SIZEOF_REGISTER == 8
6025                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6026                                 opcode = OP_ATOMIC_ADD_I8;
6027 #endif
6028                         if (opcode) {
6029                                 if (!mono_arch_opcode_supported (opcode))
6030                                         return NULL;
6031                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6032                                 ins_iconst->inst_c0 = 1;
6033                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6034                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6035
6036                                 MONO_INST_NEW (cfg, ins, opcode);
6037                                 ins->dreg = mono_alloc_ireg (cfg);
6038                                 ins->inst_basereg = args [0]->dreg;
6039                                 ins->inst_offset = 0;
6040                                 ins->sreg2 = ins_iconst->dreg;
6041                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6042                                 MONO_ADD_INS (cfg->cbb, ins);
6043                         }
6044                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6045                         MonoInst *ins_iconst;
6046                         guint32 opcode = 0;
6047
6048                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6049                                 opcode = OP_ATOMIC_ADD_I4;
6050                                 cfg->has_atomic_add_i4 = TRUE;
6051                         }
6052 #if SIZEOF_REGISTER == 8
6053                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6054                                 opcode = OP_ATOMIC_ADD_I8;
6055 #endif
6056                         if (opcode) {
6057                                 if (!mono_arch_opcode_supported (opcode))
6058                                         return NULL;
6059                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6060                                 ins_iconst->inst_c0 = -1;
6061                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6062                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6063
6064                                 MONO_INST_NEW (cfg, ins, opcode);
6065                                 ins->dreg = mono_alloc_ireg (cfg);
6066                                 ins->inst_basereg = args [0]->dreg;
6067                                 ins->inst_offset = 0;
6068                                 ins->sreg2 = ins_iconst->dreg;
6069                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6070                                 MONO_ADD_INS (cfg->cbb, ins);
6071                         }
6072                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6073                         guint32 opcode = 0;
6074
6075                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6076                                 opcode = OP_ATOMIC_ADD_I4;
6077                                 cfg->has_atomic_add_i4 = TRUE;
6078                         }
6079 #if SIZEOF_REGISTER == 8
6080                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6081                                 opcode = OP_ATOMIC_ADD_I8;
6082 #endif
6083                         if (opcode) {
6084                                 if (!mono_arch_opcode_supported (opcode))
6085                                         return NULL;
6086                                 MONO_INST_NEW (cfg, ins, opcode);
6087                                 ins->dreg = mono_alloc_ireg (cfg);
6088                                 ins->inst_basereg = args [0]->dreg;
6089                                 ins->inst_offset = 0;
6090                                 ins->sreg2 = args [1]->dreg;
6091                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6092                                 MONO_ADD_INS (cfg->cbb, ins);
6093                         }
6094                 }
6095                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6096                         MonoInst *f2i = NULL, *i2f;
6097                         guint32 opcode, f2i_opcode, i2f_opcode;
6098                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6099                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6100
6101                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6102                             fsig->params [0]->type == MONO_TYPE_R4) {
6103                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6104                                 f2i_opcode = OP_MOVE_F_TO_I4;
6105                                 i2f_opcode = OP_MOVE_I4_TO_F;
6106                                 cfg->has_atomic_exchange_i4 = TRUE;
6107                         }
6108 #if SIZEOF_REGISTER == 8
6109                         else if (is_ref ||
6110                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6111                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6112                                  fsig->params [0]->type == MONO_TYPE_I) {
6113                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6114                                 f2i_opcode = OP_MOVE_F_TO_I8;
6115                                 i2f_opcode = OP_MOVE_I8_TO_F;
6116                         }
6117 #else
6118                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6119                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6120                                 cfg->has_atomic_exchange_i4 = TRUE;
6121                         }
6122 #endif
6123                         else
6124                                 return NULL;
6125
6126                         if (!mono_arch_opcode_supported (opcode))
6127                                 return NULL;
6128
6129                         if (is_float) {
6130                                 /* TODO: Decompose these opcodes instead of bailing here. */
6131                                 if (COMPILE_SOFT_FLOAT (cfg))
6132                                         return NULL;
6133
6134                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6135                                 f2i->dreg = mono_alloc_ireg (cfg);
6136                                 f2i->sreg1 = args [1]->dreg;
6137                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6138                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6139                                 MONO_ADD_INS (cfg->cbb, f2i);
6140                         }
6141
6142                         MONO_INST_NEW (cfg, ins, opcode);
6143                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6144                         ins->inst_basereg = args [0]->dreg;
6145                         ins->inst_offset = 0;
6146                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6147                         MONO_ADD_INS (cfg->cbb, ins);
6148
6149                         switch (fsig->params [0]->type) {
6150                         case MONO_TYPE_I4:
6151                                 ins->type = STACK_I4;
6152                                 break;
6153                         case MONO_TYPE_I8:
6154                                 ins->type = STACK_I8;
6155                                 break;
6156                         case MONO_TYPE_I:
6157 #if SIZEOF_REGISTER == 8
6158                                 ins->type = STACK_I8;
6159 #else
6160                                 ins->type = STACK_I4;
6161 #endif
6162                                 break;
6163                         case MONO_TYPE_R4:
6164                         case MONO_TYPE_R8:
6165                                 ins->type = STACK_R8;
6166                                 break;
6167                         default:
6168                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6169                                 ins->type = STACK_OBJ;
6170                                 break;
6171                         }
6172
6173                         if (is_float) {
6174                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6175                                 i2f->dreg = mono_alloc_freg (cfg);
6176                                 i2f->sreg1 = ins->dreg;
6177                                 i2f->type = STACK_R8;
6178                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6179                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6180                                 MONO_ADD_INS (cfg->cbb, i2f);
6181
6182                                 ins = i2f;
6183                         }
6184
6185                         if (cfg->gen_write_barriers && is_ref)
6186                                 emit_write_barrier (cfg, args [0], args [1]);
6187                 }
6188                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6189                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6190                         guint32 opcode, f2i_opcode, i2f_opcode;
6191                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
6192                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6193
6194                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6195                             fsig->params [1]->type == MONO_TYPE_R4) {
6196                                 opcode = OP_ATOMIC_CAS_I4;
6197                                 f2i_opcode = OP_MOVE_F_TO_I4;
6198                                 i2f_opcode = OP_MOVE_I4_TO_F;
6199                                 cfg->has_atomic_cas_i4 = TRUE;
6200                         }
6201 #if SIZEOF_REGISTER == 8
6202                         else if (is_ref ||
6203                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6204                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6205                                  fsig->params [1]->type == MONO_TYPE_I) {
6206                                 opcode = OP_ATOMIC_CAS_I8;
6207                                 f2i_opcode = OP_MOVE_F_TO_I8;
6208                                 i2f_opcode = OP_MOVE_I8_TO_F;
6209                         }
6210 #else
6211                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6212                                 opcode = OP_ATOMIC_CAS_I4;
6213                                 cfg->has_atomic_cas_i4 = TRUE;
6214                         }
6215 #endif
6216                         else
6217                                 return NULL;
6218
6219                         if (!mono_arch_opcode_supported (opcode))
6220                                 return NULL;
6221
6222                         if (is_float) {
6223                                 /* TODO: Decompose these opcodes instead of bailing here. */
6224                                 if (COMPILE_SOFT_FLOAT (cfg))
6225                                         return NULL;
6226
6227                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6228                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6229                                 f2i_new->sreg1 = args [1]->dreg;
6230                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6231                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6232                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6233
6234                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6235                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6236                                 f2i_cmp->sreg1 = args [2]->dreg;
6237                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6238                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6239                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6240                         }
6241
6242                         MONO_INST_NEW (cfg, ins, opcode);
6243                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6244                         ins->sreg1 = args [0]->dreg;
6245                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6246                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6247                         MONO_ADD_INS (cfg->cbb, ins);
6248
6249                         switch (fsig->params [1]->type) {
6250                         case MONO_TYPE_I4:
6251                                 ins->type = STACK_I4;
6252                                 break;
6253                         case MONO_TYPE_I8:
6254                                 ins->type = STACK_I8;
6255                                 break;
6256                         case MONO_TYPE_I:
6257 #if SIZEOF_REGISTER == 8
6258                                 ins->type = STACK_I8;
6259 #else
6260                                 ins->type = STACK_I4;
6261 #endif
6262                                 break;
6263                         case MONO_TYPE_R4:
6264                         case MONO_TYPE_R8:
6265                                 ins->type = STACK_R8;
6266                                 break;
6267                         default:
6268                                 g_assert (mini_type_is_reference (cfg, fsig->params [1]));
6269                                 ins->type = STACK_OBJ;
6270                                 break;
6271                         }
6272
6273                         if (is_float) {
6274                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6275                                 i2f->dreg = mono_alloc_freg (cfg);
6276                                 i2f->sreg1 = ins->dreg;
6277                                 i2f->type = STACK_R8;
6278                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6279                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6280                                 MONO_ADD_INS (cfg->cbb, i2f);
6281
6282                                 ins = i2f;
6283                         }
6284
6285                         if (cfg->gen_write_barriers && is_ref)
6286                                 emit_write_barrier (cfg, args [0], args [1]);
6287                 }
6288                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6289                          fsig->params [1]->type == MONO_TYPE_I4) {
6290                         MonoInst *cmp, *ceq;
6291
6292                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6293                                 return NULL;
6294
6295                         /* int32 r = CAS (location, value, comparand); */
6296                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6297                         ins->dreg = alloc_ireg (cfg);
6298                         ins->sreg1 = args [0]->dreg;
6299                         ins->sreg2 = args [1]->dreg;
6300                         ins->sreg3 = args [2]->dreg;
6301                         ins->type = STACK_I4;
6302                         MONO_ADD_INS (cfg->cbb, ins);
6303
6304                         /* bool result = r == comparand; */
6305                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6306                         cmp->sreg1 = ins->dreg;
6307                         cmp->sreg2 = args [2]->dreg;
6308                         cmp->type = STACK_I4;
6309                         MONO_ADD_INS (cfg->cbb, cmp);
6310
6311                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6312                         ceq->dreg = alloc_ireg (cfg);
6313                         ceq->type = STACK_I4;
6314                         MONO_ADD_INS (cfg->cbb, ceq);
6315
6316                         /* *success = result; */
6317                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6318
6319                         cfg->has_atomic_cas_i4 = TRUE;
6320                 }
6321                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6322                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6323
6324                 if (ins)
6325                         return ins;
6326         } else if (cmethod->klass->image == mono_defaults.corlib &&
6327                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6328                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6329                 ins = NULL;
6330
6331                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6332                         guint32 opcode = 0;
6333                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6334                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6335
6336                         if (fsig->params [0]->type == MONO_TYPE_I1)
6337                                 opcode = OP_ATOMIC_LOAD_I1;
6338                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6339                                 opcode = OP_ATOMIC_LOAD_U1;
6340                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6341                                 opcode = OP_ATOMIC_LOAD_I2;
6342                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6343                                 opcode = OP_ATOMIC_LOAD_U2;
6344                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6345                                 opcode = OP_ATOMIC_LOAD_I4;
6346                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6347                                 opcode = OP_ATOMIC_LOAD_U4;
6348                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6349                                 opcode = OP_ATOMIC_LOAD_R4;
6350                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6351                                 opcode = OP_ATOMIC_LOAD_R8;
6352 #if SIZEOF_REGISTER == 8
6353                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6354                                 opcode = OP_ATOMIC_LOAD_I8;
6355                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6356                                 opcode = OP_ATOMIC_LOAD_U8;
6357 #else
6358                         else if (fsig->params [0]->type == MONO_TYPE_I)
6359                                 opcode = OP_ATOMIC_LOAD_I4;
6360                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6361                                 opcode = OP_ATOMIC_LOAD_U4;
6362 #endif
6363
6364                         if (opcode) {
6365                                 if (!mono_arch_opcode_supported (opcode))
6366                                         return NULL;
6367
6368                                 MONO_INST_NEW (cfg, ins, opcode);
6369                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6370                                 ins->sreg1 = args [0]->dreg;
6371                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6372                                 MONO_ADD_INS (cfg->cbb, ins);
6373
6374                                 switch (fsig->params [0]->type) {
6375                                 case MONO_TYPE_BOOLEAN:
6376                                 case MONO_TYPE_I1:
6377                                 case MONO_TYPE_U1:
6378                                 case MONO_TYPE_I2:
6379                                 case MONO_TYPE_U2:
6380                                 case MONO_TYPE_I4:
6381                                 case MONO_TYPE_U4:
6382                                         ins->type = STACK_I4;
6383                                         break;
6384                                 case MONO_TYPE_I8:
6385                                 case MONO_TYPE_U8:
6386                                         ins->type = STACK_I8;
6387                                         break;
6388                                 case MONO_TYPE_I:
6389                                 case MONO_TYPE_U:
6390 #if SIZEOF_REGISTER == 8
6391                                         ins->type = STACK_I8;
6392 #else
6393                                         ins->type = STACK_I4;
6394 #endif
6395                                         break;
6396                                 case MONO_TYPE_R4:
6397                                 case MONO_TYPE_R8:
6398                                         ins->type = STACK_R8;
6399                                         break;
6400                                 default:
6401                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
6402                                         ins->type = STACK_OBJ;
6403                                         break;
6404                                 }
6405                         }
6406                 }
6407
6408                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6409                         guint32 opcode = 0;
6410                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6411
6412                         if (fsig->params [0]->type == MONO_TYPE_I1)
6413                                 opcode = OP_ATOMIC_STORE_I1;
6414                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6415                                 opcode = OP_ATOMIC_STORE_U1;
6416                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6417                                 opcode = OP_ATOMIC_STORE_I2;
6418                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6419                                 opcode = OP_ATOMIC_STORE_U2;
6420                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6421                                 opcode = OP_ATOMIC_STORE_I4;
6422                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6423                                 opcode = OP_ATOMIC_STORE_U4;
6424                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6425                                 opcode = OP_ATOMIC_STORE_R4;
6426                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6427                                 opcode = OP_ATOMIC_STORE_R8;
6428 #if SIZEOF_REGISTER == 8
6429                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6430                                 opcode = OP_ATOMIC_STORE_I8;
6431                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6432                                 opcode = OP_ATOMIC_STORE_U8;
6433 #else
6434                         else if (fsig->params [0]->type == MONO_TYPE_I)
6435                                 opcode = OP_ATOMIC_STORE_I4;
6436                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6437                                 opcode = OP_ATOMIC_STORE_U4;
6438 #endif
6439
6440                         if (opcode) {
6441                                 if (!mono_arch_opcode_supported (opcode))
6442                                         return NULL;
6443
6444                                 MONO_INST_NEW (cfg, ins, opcode);
6445                                 ins->dreg = args [0]->dreg;
6446                                 ins->sreg1 = args [1]->dreg;
6447                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6448                                 MONO_ADD_INS (cfg->cbb, ins);
6449
6450                                 if (cfg->gen_write_barriers && is_ref)
6451                                         emit_write_barrier (cfg, args [0], args [1]);
6452                         }
6453                 }
6454
6455                 if (ins)
6456                         return ins;
6457         } else if (cmethod->klass->image == mono_defaults.corlib &&
6458                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6459                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6460                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6461                         if (should_insert_brekpoint (cfg->method)) {
6462                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6463                         } else {
6464                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6465                                 MONO_ADD_INS (cfg->cbb, ins);
6466                         }
6467                         return ins;
6468                 }
6469         } else if (cmethod->klass->image == mono_defaults.corlib &&
6470                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6471                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6472                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6473 #ifdef TARGET_WIN32
6474                         EMIT_NEW_ICONST (cfg, ins, 1);
6475 #else
6476                         EMIT_NEW_ICONST (cfg, ins, 0);
6477 #endif
6478                 }
6479         } else if (cmethod->klass == mono_defaults.math_class) {
6480                 /* 
6481                  * There is general branchless code for Min/Max, but it does not work for 
6482                  * all inputs:
6483                  * http://everything2.com/?node_id=1051618
6484                  */
6485         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6486                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6487                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6488                    !strcmp (cmethod->klass->name, "Selector")) {
6489 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6490                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6491                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6492                     cfg->compile_aot) {
6493                         MonoInst *pi;
6494                         MonoJumpInfoToken *ji;
6495                         MonoString *s;
6496
6497                         cfg->disable_llvm = TRUE;
6498
6499                         if (args [0]->opcode == OP_GOT_ENTRY) {
6500                                 pi = args [0]->inst_p1;
6501                                 g_assert (pi->opcode == OP_PATCH_INFO);
6502                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6503                                 ji = pi->inst_p0;
6504                         } else {
6505                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6506                                 ji = args [0]->inst_p0;
6507                         }
6508
6509                         NULLIFY_INS (args [0]);
6510
6511                         // FIXME: Ugly
6512                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6513                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6514                         ins->dreg = mono_alloc_ireg (cfg);
6515                         // FIXME: Leaks
6516                         ins->inst_p0 = mono_string_to_utf8 (s);
6517                         MONO_ADD_INS (cfg->cbb, ins);
6518                         return ins;
6519                 }
6520 #endif
6521         }
6522
6523 #ifdef MONO_ARCH_SIMD_INTRINSICS
6524         if (cfg->opt & MONO_OPT_SIMD) {
6525                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6526                 if (ins)
6527                         return ins;
6528         }
6529 #endif
6530
6531         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6532         if (ins)
6533                 return ins;
6534
6535         if (COMPILE_LLVM (cfg)) {
6536                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6537                 if (ins)
6538                         return ins;
6539         }
6540
6541         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6542 }
6543
6544 /*
6545  * This entry point could be used later for arbitrary method
6546  * redirection.
6547  */
6548 inline static MonoInst*
6549 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6550                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6551 {
6552         if (method->klass == mono_defaults.string_class) {
6553                 /* managed string allocation support */
6554                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6555                         MonoInst *iargs [2];
6556                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6557                         MonoMethod *managed_alloc = NULL;
6558
6559                         g_assert (vtable); /*Should not fail since it System.String*/
6560 #ifndef MONO_CROSS_COMPILE
6561                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6562 #endif
6563                         if (!managed_alloc)
6564                                 return NULL;
6565                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6566                         iargs [1] = args [0];
6567                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6568                 }
6569         }
6570         return NULL;
6571 }
6572
6573 static void
6574 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6575 {
6576         MonoInst *store, *temp;
6577         int i;
6578
6579         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6580                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6581
6582                 /*
6583                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6584                  * would be different than the MonoInst's used to represent arguments, and
6585                  * the ldelema implementation can't deal with that.
6586                  * Solution: When ldelema is used on an inline argument, create a var for 
6587                  * it, emit ldelema on that var, and emit the saving code below in
6588                  * inline_method () if needed.
6589                  */
6590                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6591                 cfg->args [i] = temp;
6592                 /* This uses cfg->args [i] which is set by the preceeding line */
6593                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6594                 store->cil_code = sp [0]->cil_code;
6595                 sp++;
6596         }
6597 }
6598
6599 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6600 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6601
6602 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6603 static gboolean
6604 check_inline_called_method_name_limit (MonoMethod *called_method)
6605 {
6606         int strncmp_result;
6607         static const char *limit = NULL;
6608         
6609         if (limit == NULL) {
6610                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6611
6612                 if (limit_string != NULL)
6613                         limit = limit_string;
6614                 else
6615                         limit = "";
6616         }
6617
6618         if (limit [0] != '\0') {
6619                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6620
6621                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6622                 g_free (called_method_name);
6623         
6624                 //return (strncmp_result <= 0);
6625                 return (strncmp_result == 0);
6626         } else {
6627                 return TRUE;
6628         }
6629 }
6630 #endif
6631
6632 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6633 static gboolean
6634 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6635 {
6636         int strncmp_result;
6637         static const char *limit = NULL;
6638         
6639         if (limit == NULL) {
6640                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6641                 if (limit_string != NULL) {
6642                         limit = limit_string;
6643                 } else {
6644                         limit = "";
6645                 }
6646         }
6647
6648         if (limit [0] != '\0') {
6649                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6650
6651                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6652                 g_free (caller_method_name);
6653         
6654                 //return (strncmp_result <= 0);
6655                 return (strncmp_result == 0);
6656         } else {
6657                 return TRUE;
6658         }
6659 }
6660 #endif
6661
6662 static void
6663 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6664 {
6665         static double r8_0 = 0.0;
6666         static float r4_0 = 0.0;
6667         MonoInst *ins;
6668         int t;
6669
6670         rtype = mini_get_underlying_type (cfg, rtype);
6671         t = rtype->type;
6672
6673         if (rtype->byref) {
6674                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6675         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6676                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6677         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6678                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6679         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6680                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6681                 ins->type = STACK_R4;
6682                 ins->inst_p0 = (void*)&r4_0;
6683                 ins->dreg = dreg;
6684                 MONO_ADD_INS (cfg->cbb, ins);
6685         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6686                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6687                 ins->type = STACK_R8;
6688                 ins->inst_p0 = (void*)&r8_0;
6689                 ins->dreg = dreg;
6690                 MONO_ADD_INS (cfg->cbb, ins);
6691         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6692                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6693                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6694         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6695                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6696         } else {
6697                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6698         }
6699 }
6700
6701 static void
6702 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6703 {
6704         int t;
6705
6706         rtype = mini_get_underlying_type (cfg, rtype);
6707         t = rtype->type;
6708
6709         if (rtype->byref) {
6710                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6711         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6712                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6713         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6714                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6715         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6716                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6717         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6718                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6719         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6720                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6721                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6722         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6723                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6724         } else {
6725                 emit_init_rvar (cfg, dreg, rtype);
6726         }
6727 }
6728
6729 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6730 static void
6731 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6732 {
6733         MonoInst *var = cfg->locals [local];
6734         if (COMPILE_SOFT_FLOAT (cfg)) {
6735                 MonoInst *store;
6736                 int reg = alloc_dreg (cfg, var->type);
6737                 emit_init_rvar (cfg, reg, type);
6738                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6739         } else {
6740                 if (init)
6741                         emit_init_rvar (cfg, var->dreg, type);
6742                 else
6743                         emit_dummy_init_rvar (cfg, var->dreg, type);
6744         }
6745 }
6746
6747 /*
6748  * inline_method:
6749  *
6750  *   Return the cost of inlining CMETHOD.
6751  */
6752 static int
6753 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6754                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6755 {
6756         MonoInst *ins, *rvar = NULL;
6757         MonoMethodHeader *cheader;
6758         MonoBasicBlock *ebblock, *sbblock;
6759         int i, costs;
6760         MonoMethod *prev_inlined_method;
6761         MonoInst **prev_locals, **prev_args;
6762         MonoType **prev_arg_types;
6763         guint prev_real_offset;
6764         GHashTable *prev_cbb_hash;
6765         MonoBasicBlock **prev_cil_offset_to_bb;
6766         MonoBasicBlock *prev_cbb;
6767         unsigned char* prev_cil_start;
6768         guint32 prev_cil_offset_to_bb_len;
6769         MonoMethod *prev_current_method;
6770         MonoGenericContext *prev_generic_context;
6771         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6772
6773         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6774
6775 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6776         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6777                 return 0;
6778 #endif
6779 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6780         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6781                 return 0;
6782 #endif
6783
6784         if (!fsig)
6785                 fsig = mono_method_signature (cmethod);
6786
6787         if (cfg->verbose_level > 2)
6788                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6789
6790         if (!cmethod->inline_info) {
6791                 cfg->stat_inlineable_methods++;
6792                 cmethod->inline_info = 1;
6793         }
6794
6795         /* allocate local variables */
6796         cheader = mono_method_get_header (cmethod);
6797
6798         if (cheader == NULL || mono_loader_get_last_error ()) {
6799                 MonoLoaderError *error = mono_loader_get_last_error ();
6800
6801                 if (cheader)
6802                         mono_metadata_free_mh (cheader);
6803                 if (inline_always && error)
6804                         mono_cfg_set_exception (cfg, error->exception_type);
6805
6806                 mono_loader_clear_error ();
6807                 return 0;
6808         }
6809
6810         /*Must verify before creating locals as it can cause the JIT to assert.*/
6811         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6812                 mono_metadata_free_mh (cheader);
6813                 return 0;
6814         }
6815
6816         /* allocate space to store the return value */
6817         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6818                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6819         }
6820
6821         prev_locals = cfg->locals;
6822         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6823         for (i = 0; i < cheader->num_locals; ++i)
6824                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6825
6826         /* allocate start and end blocks */
6827         /* This is needed so if the inline is aborted, we can clean up */
6828         NEW_BBLOCK (cfg, sbblock);
6829         sbblock->real_offset = real_offset;
6830
6831         NEW_BBLOCK (cfg, ebblock);
6832         ebblock->block_num = cfg->num_bblocks++;
6833         ebblock->real_offset = real_offset;
6834
6835         prev_args = cfg->args;
6836         prev_arg_types = cfg->arg_types;
6837         prev_inlined_method = cfg->inlined_method;
6838         cfg->inlined_method = cmethod;
6839         cfg->ret_var_set = FALSE;
6840         cfg->inline_depth ++;
6841         prev_real_offset = cfg->real_offset;
6842         prev_cbb_hash = cfg->cbb_hash;
6843         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6844         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6845         prev_cil_start = cfg->cil_start;
6846         prev_cbb = cfg->cbb;
6847         prev_current_method = cfg->current_method;
6848         prev_generic_context = cfg->generic_context;
6849         prev_ret_var_set = cfg->ret_var_set;
6850         prev_disable_inline = cfg->disable_inline;
6851
6852         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6853                 virtual = TRUE;
6854
6855         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6856
6857         ret_var_set = cfg->ret_var_set;
6858
6859         cfg->inlined_method = prev_inlined_method;
6860         cfg->real_offset = prev_real_offset;
6861         cfg->cbb_hash = prev_cbb_hash;
6862         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6863         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6864         cfg->cil_start = prev_cil_start;
6865         cfg->locals = prev_locals;
6866         cfg->args = prev_args;
6867         cfg->arg_types = prev_arg_types;
6868         cfg->current_method = prev_current_method;
6869         cfg->generic_context = prev_generic_context;
6870         cfg->ret_var_set = prev_ret_var_set;
6871         cfg->disable_inline = prev_disable_inline;
6872         cfg->inline_depth --;
6873
6874         if ((costs >= 0 && costs < 60) || inline_always) {
6875                 if (cfg->verbose_level > 2)
6876                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6877                 
6878                 cfg->stat_inlined_methods++;
6879
6880                 /* always add some code to avoid block split failures */
6881                 MONO_INST_NEW (cfg, ins, OP_NOP);
6882                 MONO_ADD_INS (prev_cbb, ins);
6883
6884                 prev_cbb->next_bb = sbblock;
6885                 link_bblock (cfg, prev_cbb, sbblock);
6886
6887                 /* 
6888                  * Get rid of the begin and end bblocks if possible to aid local
6889                  * optimizations.
6890                  */
6891                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6892
6893                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6894                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6895
6896                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6897                         MonoBasicBlock *prev = ebblock->in_bb [0];
6898                         mono_merge_basic_blocks (cfg, prev, ebblock);
6899                         cfg->cbb = prev;
6900                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6901                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6902                                 cfg->cbb = prev_cbb;
6903                         }
6904                 } else {
6905                         /* 
6906                          * Its possible that the rvar is set in some prev bblock, but not in others.
6907                          * (#1835).
6908                          */
6909                         if (rvar) {
6910                                 MonoBasicBlock *bb;
6911
6912                                 for (i = 0; i < ebblock->in_count; ++i) {
6913                                         bb = ebblock->in_bb [i];
6914
6915                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6916                                                 cfg->cbb = bb;
6917
6918                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6919                                         }
6920                                 }
6921                         }
6922
6923                         cfg->cbb = ebblock;
6924                 }
6925
6926                 if (out_cbb)
6927                         *out_cbb = cfg->cbb;
6928
6929                 if (rvar) {
6930                         /*
6931                          * If the inlined method contains only a throw, then the ret var is not 
6932                          * set, so set it to a dummy value.
6933                          */
6934                         if (!ret_var_set)
6935                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6936
6937                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6938                         *sp++ = ins;
6939                 }
6940                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6941                 return costs + 1;
6942         } else {
6943                 if (cfg->verbose_level > 2)
6944                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6945                 cfg->exception_type = MONO_EXCEPTION_NONE;
6946                 mono_loader_clear_error ();
6947
6948                 /* This gets rid of the newly added bblocks */
6949                 cfg->cbb = prev_cbb;
6950         }
6951         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6952         return 0;
6953 }
6954
6955 /*
6956  * Some of these comments may well be out-of-date.
6957  * Design decisions: we do a single pass over the IL code (and we do bblock 
6958  * splitting/merging in the few cases when it's required: a back jump to an IL
6959  * address that was not already seen as bblock starting point).
6960  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6961  * Complex operations are decomposed in simpler ones right away. We need to let the 
6962  * arch-specific code peek and poke inside this process somehow (except when the 
6963  * optimizations can take advantage of the full semantic info of coarse opcodes).
6964  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6965  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6966  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6967  * opcode with value bigger than OP_LAST.
6968  * At this point the IR can be handed over to an interpreter, a dumb code generator
6969  * or to the optimizing code generator that will translate it to SSA form.
6970  *
6971  * Profiling directed optimizations.
6972  * We may compile by default with few or no optimizations and instrument the code
6973  * or the user may indicate what methods to optimize the most either in a config file
6974  * or through repeated runs where the compiler applies offline the optimizations to 
6975  * each method and then decides if it was worth it.
6976  */
6977
6978 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6979 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6980 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6981 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6982 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6983 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6984 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6985 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6986
6987 /* offset from br.s -> br like opcodes */
6988 #define BIG_BRANCH_OFFSET 13
6989
6990 static gboolean
6991 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6992 {
6993         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6994
6995         return b == NULL || b == bb;
6996 }
6997
6998 static int
6999 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7000 {
7001         unsigned char *ip = start;
7002         unsigned char *target;
7003         int i;
7004         guint cli_addr;
7005         MonoBasicBlock *bblock;
7006         const MonoOpcode *opcode;
7007
7008         while (ip < end) {
7009                 cli_addr = ip - start;
7010                 i = mono_opcode_value ((const guint8 **)&ip, end);
7011                 if (i < 0)
7012                         UNVERIFIED;
7013                 opcode = &mono_opcodes [i];
7014                 switch (opcode->argument) {
7015                 case MonoInlineNone:
7016                         ip++; 
7017                         break;
7018                 case MonoInlineString:
7019                 case MonoInlineType:
7020                 case MonoInlineField:
7021                 case MonoInlineMethod:
7022                 case MonoInlineTok:
7023                 case MonoInlineSig:
7024                 case MonoShortInlineR:
7025                 case MonoInlineI:
7026                         ip += 5;
7027                         break;
7028                 case MonoInlineVar:
7029                         ip += 3;
7030                         break;
7031                 case MonoShortInlineVar:
7032                 case MonoShortInlineI:
7033                         ip += 2;
7034                         break;
7035                 case MonoShortInlineBrTarget:
7036                         target = start + cli_addr + 2 + (signed char)ip [1];
7037                         GET_BBLOCK (cfg, bblock, target);
7038                         ip += 2;
7039                         if (ip < end)
7040                                 GET_BBLOCK (cfg, bblock, ip);
7041                         break;
7042                 case MonoInlineBrTarget:
7043                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7044                         GET_BBLOCK (cfg, bblock, target);
7045                         ip += 5;
7046                         if (ip < end)
7047                                 GET_BBLOCK (cfg, bblock, ip);
7048                         break;
7049                 case MonoInlineSwitch: {
7050                         guint32 n = read32 (ip + 1);
7051                         guint32 j;
7052                         ip += 5;
7053                         cli_addr += 5 + 4 * n;
7054                         target = start + cli_addr;
7055                         GET_BBLOCK (cfg, bblock, target);
7056                         
7057                         for (j = 0; j < n; ++j) {
7058                                 target = start + cli_addr + (gint32)read32 (ip);
7059                                 GET_BBLOCK (cfg, bblock, target);
7060                                 ip += 4;
7061                         }
7062                         break;
7063                 }
7064                 case MonoInlineR:
7065                 case MonoInlineI8:
7066                         ip += 9;
7067                         break;
7068                 default:
7069                         g_assert_not_reached ();
7070                 }
7071
7072                 if (i == CEE_THROW) {
7073                         unsigned char *bb_start = ip - 1;
7074                         
7075                         /* Find the start of the bblock containing the throw */
7076                         bblock = NULL;
7077                         while ((bb_start >= start) && !bblock) {
7078                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7079                                 bb_start --;
7080                         }
7081                         if (bblock)
7082                                 bblock->out_of_line = 1;
7083                 }
7084         }
7085         return 0;
7086 unverified:
7087 exception_exit:
7088         *pos = ip;
7089         return 1;
7090 }
7091
7092 static inline MonoMethod *
7093 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7094 {
7095         MonoMethod *method;
7096
7097         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7098                 method = mono_method_get_wrapper_data (m, token);
7099                 if (context) {
7100                         MonoError error;
7101                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7102                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7103                 }
7104         } else {
7105                 method = mono_get_method_full (m->klass->image, token, klass, context);
7106         }
7107
7108         return method;
7109 }
7110
7111 static inline MonoMethod *
7112 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7113 {
7114         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7115
7116         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7117                 return NULL;
7118
7119         return method;
7120 }
7121
7122 static inline MonoClass*
7123 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7124 {
7125         MonoError error;
7126         MonoClass *klass;
7127
7128         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7129                 klass = mono_method_get_wrapper_data (method, token);
7130                 if (context)
7131                         klass = mono_class_inflate_generic_class (klass, context);
7132         } else {
7133                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7134                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7135         }
7136         if (klass)
7137                 mono_class_init (klass);
7138         return klass;
7139 }
7140
7141 static inline MonoMethodSignature*
7142 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7143 {
7144         MonoMethodSignature *fsig;
7145
7146         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7147                 MonoError error;
7148
7149                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7150                 if (context) {
7151                         fsig = mono_inflate_generic_signature (fsig, context, &error);
7152                         // FIXME:
7153                         g_assert (mono_error_ok (&error));
7154                 }
7155         } else {
7156                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7157         }
7158         return fsig;
7159 }
7160
7161 /*
7162  * Returns TRUE if the JIT should abort inlining because "callee"
7163  * is influenced by security attributes.
7164  */
7165 static
7166 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7167 {
7168         guint32 result;
7169         
7170         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
7171                 return TRUE;
7172         }
7173         
7174         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
7175         if (result == MONO_JIT_SECURITY_OK)
7176                 return FALSE;
7177
7178         if (result == MONO_JIT_LINKDEMAND_ECMA) {
7179                 /* Generate code to throw a SecurityException before the actual call/link */
7180                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7181                 MonoInst *args [2];
7182
7183                 NEW_ICONST (cfg, args [0], 4);
7184                 NEW_METHODCONST (cfg, args [1], caller);
7185                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
7186         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
7187                  /* don't hide previous results */
7188                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
7189                 cfg->exception_data = result;
7190                 return TRUE;
7191         }
7192         
7193         return FALSE;
7194 }
7195
7196 static MonoMethod*
7197 throw_exception (void)
7198 {
7199         static MonoMethod *method = NULL;
7200
7201         if (!method) {
7202                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7203                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7204         }
7205         g_assert (method);
7206         return method;
7207 }
7208
7209 static void
7210 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7211 {
7212         MonoMethod *thrower = throw_exception ();
7213         MonoInst *args [1];
7214
7215         EMIT_NEW_PCONST (cfg, args [0], ex);
7216         mono_emit_method_call (cfg, thrower, args, NULL);
7217 }
7218
7219 /*
7220  * Return the original method is a wrapper is specified. We can only access 
7221  * the custom attributes from the original method.
7222  */
7223 static MonoMethod*
7224 get_original_method (MonoMethod *method)
7225 {
7226         if (method->wrapper_type == MONO_WRAPPER_NONE)
7227                 return method;
7228
7229         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7230         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7231                 return NULL;
7232
7233         /* in other cases we need to find the original method */
7234         return mono_marshal_method_from_wrapper (method);
7235 }
7236
7237 static void
7238 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
7239                                           MonoBasicBlock *bblock, unsigned char *ip)
7240 {
7241         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7242         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7243         if (ex)
7244                 emit_throw_exception (cfg, ex);
7245 }
7246
7247 static void
7248 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
7249                                          MonoBasicBlock *bblock, unsigned char *ip)
7250 {
7251         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7252         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7253         if (ex)
7254                 emit_throw_exception (cfg, ex);
7255 }
7256
7257 /*
7258  * Check that the IL instructions at ip are the array initialization
7259  * sequence and return the pointer to the data and the size.
7260  */
7261 static const char*
7262 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7263 {
7264         /*
7265          * newarr[System.Int32]
7266          * dup
7267          * ldtoken field valuetype ...
7268          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7269          */
7270         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7271                 MonoError error;
7272                 guint32 token = read32 (ip + 7);
7273                 guint32 field_token = read32 (ip + 2);
7274                 guint32 field_index = field_token & 0xffffff;
7275                 guint32 rva;
7276                 const char *data_ptr;
7277                 int size = 0;
7278                 MonoMethod *cmethod;
7279                 MonoClass *dummy_class;
7280                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7281                 int dummy_align;
7282
7283                 if (!field) {
7284                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7285                         return NULL;
7286                 }
7287
7288                 *out_field_token = field_token;
7289
7290                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7291                 if (!cmethod)
7292                         return NULL;
7293                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7294                         return NULL;
7295                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7296                 case MONO_TYPE_BOOLEAN:
7297                 case MONO_TYPE_I1:
7298                 case MONO_TYPE_U1:
7299                         size = 1; break;
7300                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7301 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7302                 case MONO_TYPE_CHAR:
7303                 case MONO_TYPE_I2:
7304                 case MONO_TYPE_U2:
7305                         size = 2; break;
7306                 case MONO_TYPE_I4:
7307                 case MONO_TYPE_U4:
7308                 case MONO_TYPE_R4:
7309                         size = 4; break;
7310                 case MONO_TYPE_R8:
7311                 case MONO_TYPE_I8:
7312                 case MONO_TYPE_U8:
7313                         size = 8; break;
7314 #endif
7315                 default:
7316                         return NULL;
7317                 }
7318                 size *= len;
7319                 if (size > mono_type_size (field->type, &dummy_align))
7320                     return NULL;
7321                 *out_size = size;
7322                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7323                 if (!image_is_dynamic (method->klass->image)) {
7324                         field_index = read32 (ip + 2) & 0xffffff;
7325                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7326                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7327                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7328                         /* for aot code we do the lookup on load */
7329                         if (aot && data_ptr)
7330                                 return GUINT_TO_POINTER (rva);
7331                 } else {
7332                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7333                         g_assert (!aot);
7334                         data_ptr = mono_field_get_data (field);
7335                 }
7336                 return data_ptr;
7337         }
7338         return NULL;
7339 }
7340
7341 static void
7342 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7343 {
7344         char *method_fname = mono_method_full_name (method, TRUE);
7345         char *method_code;
7346         MonoMethodHeader *header = mono_method_get_header (method);
7347
7348         if (header->code_size == 0)
7349                 method_code = g_strdup ("method body is empty.");
7350         else
7351                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7352         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7353         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7354         g_free (method_fname);
7355         g_free (method_code);
7356         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7357 }
7358
7359 static void
7360 set_exception_object (MonoCompile *cfg, MonoException *exception)
7361 {
7362         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7363         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7364         cfg->exception_ptr = exception;
7365 }
7366
7367 static void
7368 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7369 {
7370         MonoInst *ins;
7371         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7372         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7373                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7374                 /* Optimize reg-reg moves away */
7375                 /* 
7376                  * Can't optimize other opcodes, since sp[0] might point to
7377                  * the last ins of a decomposed opcode.
7378                  */
7379                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7380         } else {
7381                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7382         }
7383 }
7384
7385 /*
7386  * ldloca inhibits many optimizations so try to get rid of it in common
7387  * cases.
7388  */
7389 static inline unsigned char *
7390 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7391 {
7392         int local, token;
7393         MonoClass *klass;
7394         MonoType *type;
7395
7396         if (size == 1) {
7397                 local = ip [1];
7398                 ip += 2;
7399         } else {
7400                 local = read16 (ip + 2);
7401                 ip += 4;
7402         }
7403         
7404         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7405                 /* From the INITOBJ case */
7406                 token = read32 (ip + 2);
7407                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7408                 CHECK_TYPELOAD (klass);
7409                 type = mini_get_underlying_type (cfg, &klass->byval_arg);
7410                 emit_init_local (cfg, local, type, TRUE);
7411                 return ip + 6;
7412         }
7413  exception_exit:
7414         return NULL;
7415 }
7416
7417 static gboolean
7418 is_exception_class (MonoClass *class)
7419 {
7420         while (class) {
7421                 if (class == mono_defaults.exception_class)
7422                         return TRUE;
7423                 class = class->parent;
7424         }
7425         return FALSE;
7426 }
7427
7428 /*
7429  * is_jit_optimizer_disabled:
7430  *
7431  *   Determine whenever M's assembly has a DebuggableAttribute with the
7432  * IsJITOptimizerDisabled flag set.
7433  */
7434 static gboolean
7435 is_jit_optimizer_disabled (MonoMethod *m)
7436 {
7437         MonoAssembly *ass = m->klass->image->assembly;
7438         MonoCustomAttrInfo* attrs;
7439         static MonoClass *klass;
7440         int i;
7441         gboolean val = FALSE;
7442
7443         g_assert (ass);
7444         if (ass->jit_optimizer_disabled_inited)
7445                 return ass->jit_optimizer_disabled;
7446
7447         if (!klass)
7448                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7449         if (!klass) {
7450                 /* Linked away */
7451                 ass->jit_optimizer_disabled = FALSE;
7452                 mono_memory_barrier ();
7453                 ass->jit_optimizer_disabled_inited = TRUE;
7454                 return FALSE;
7455         }
7456
7457         attrs = mono_custom_attrs_from_assembly (ass);
7458         if (attrs) {
7459                 for (i = 0; i < attrs->num_attrs; ++i) {
7460                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7461                         const gchar *p;
7462                         int len;
7463                         MonoMethodSignature *sig;
7464
7465                         if (!attr->ctor || attr->ctor->klass != klass)
7466                                 continue;
7467                         /* Decode the attribute. See reflection.c */
7468                         len = attr->data_size;
7469                         p = (const char*)attr->data;
7470                         g_assert (read16 (p) == 0x0001);
7471                         p += 2;
7472
7473                         // FIXME: Support named parameters
7474                         sig = mono_method_signature (attr->ctor);
7475                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7476                                 continue;
7477                         /* Two boolean arguments */
7478                         p ++;
7479                         val = *p;
7480                 }
7481                 mono_custom_attrs_free (attrs);
7482         }
7483
7484         ass->jit_optimizer_disabled = val;
7485         mono_memory_barrier ();
7486         ass->jit_optimizer_disabled_inited = TRUE;
7487
7488         return val;
7489 }
7490
7491 static gboolean
7492 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7493 {
7494         gboolean supported_tail_call;
7495         int i;
7496
7497 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7498         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7499 #else
7500         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7501 #endif
7502
7503         for (i = 0; i < fsig->param_count; ++i) {
7504                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7505                         /* These can point to the current method's stack */
7506                         supported_tail_call = FALSE;
7507         }
7508         if (fsig->hasthis && cmethod->klass->valuetype)
7509                 /* this might point to the current method's stack */
7510                 supported_tail_call = FALSE;
7511         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7512                 supported_tail_call = FALSE;
7513         if (cfg->method->save_lmf)
7514                 supported_tail_call = FALSE;
7515         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7516                 supported_tail_call = FALSE;
7517         if (call_opcode != CEE_CALL)
7518                 supported_tail_call = FALSE;
7519
7520         /* Debugging support */
7521 #if 0
7522         if (supported_tail_call) {
7523                 if (!mono_debug_count ())
7524                         supported_tail_call = FALSE;
7525         }
7526 #endif
7527
7528         return supported_tail_call;
7529 }
7530
7531 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7532  * it to the thread local value based on the tls_offset field. Every other kind of access to
7533  * the field causes an assert.
7534  */
7535 static gboolean
7536 is_magic_tls_access (MonoClassField *field)
7537 {
7538         if (strcmp (field->name, "tlsdata"))
7539                 return FALSE;
7540         if (strcmp (field->parent->name, "ThreadLocal`1"))
7541                 return FALSE;
7542         return field->parent->image == mono_defaults.corlib;
7543 }
7544
7545 /* emits the code needed to access a managed tls var (like ThreadStatic)
7546  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7547  * pointer for the current thread.
7548  * Returns the MonoInst* representing the address of the tls var.
7549  */
7550 static MonoInst*
7551 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7552 {
7553         MonoInst *addr;
7554         int static_data_reg, array_reg, dreg;
7555         int offset2_reg, idx_reg;
7556         // inlined access to the tls data
7557         // idx = (offset >> 24) - 1;
7558         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7559         static_data_reg = alloc_ireg (cfg);
7560         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7561         idx_reg = alloc_ireg (cfg);
7562         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7563         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7564         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7565         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7566         array_reg = alloc_ireg (cfg);
7567         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7568         offset2_reg = alloc_ireg (cfg);
7569         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7570         dreg = alloc_ireg (cfg);
7571         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7572         return addr;
7573 }
7574
7575 /*
7576  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7577  * this address is cached per-method in cached_tls_addr.
7578  */
7579 static MonoInst*
7580 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7581 {
7582         MonoInst *load, *addr, *temp, *store, *thread_ins;
7583         MonoClassField *offset_field;
7584
7585         if (*cached_tls_addr) {
7586                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7587                 return addr;
7588         }
7589         thread_ins = mono_get_thread_intrinsic (cfg);
7590         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7591
7592         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7593         if (thread_ins) {
7594                 MONO_ADD_INS (cfg->cbb, thread_ins);
7595         } else {
7596                 MonoMethod *thread_method;
7597                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7598                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7599         }
7600         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7601         addr->klass = mono_class_from_mono_type (tls_field->type);
7602         addr->type = STACK_MP;
7603         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7604         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7605
7606         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7607         return addr;
7608 }
7609
7610 /*
7611  * handle_ctor_call:
7612  *
7613  *   Handle calls made to ctors from NEWOBJ opcodes.
7614  *
7615  *   REF_BBLOCK will point to the current bblock after the call.
7616  */
7617 static void
7618 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7619                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7620 {
7621         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7622         MonoBasicBlock *bblock = *ref_bblock;
7623
7624         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7625                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7626                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7627                         mono_class_vtable (cfg->domain, cmethod->klass);
7628                         CHECK_TYPELOAD (cmethod->klass);
7629
7630                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7631                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7632                 } else {
7633                         if (context_used) {
7634                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7635                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7636                         } else {
7637                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7638
7639                                 CHECK_TYPELOAD (cmethod->klass);
7640                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7641                         }
7642                 }
7643         }
7644
7645         /* Avoid virtual calls to ctors if possible */
7646         if (mono_class_is_marshalbyref (cmethod->klass))
7647                 callvirt_this_arg = sp [0];
7648
7649         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7650                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7651                 CHECK_CFG_EXCEPTION;
7652         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7653                            mono_method_check_inlining (cfg, cmethod) &&
7654                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7655                 int costs;
7656
7657                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7658                         cfg->real_offset += 5;
7659
7660                         *inline_costs += costs - 5;
7661                         *ref_bblock = bblock;
7662                 } else {
7663                         INLINE_FAILURE ("inline failure");
7664                         // FIXME-VT: Clean this up
7665                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7666                                 GSHAREDVT_FAILURE(*ip);
7667                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7668                 }
7669         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7670                 MonoInst *addr;
7671
7672                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7673                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7674         } else if (context_used &&
7675                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7676                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7677                 MonoInst *cmethod_addr;
7678
7679                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7680
7681                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7682                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7683
7684                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7685         } else {
7686                 INLINE_FAILURE ("ctor call");
7687                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7688                                                                                   callvirt_this_arg, NULL, vtable_arg);
7689         }
7690  exception_exit:
7691         return;
7692 }
7693
7694 /*
7695  * mono_method_to_ir:
7696  *
7697  *   Translate the .net IL into linear IR.
7698  */
7699 int
7700 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7701                    MonoInst *return_var, MonoInst **inline_args, 
7702                    guint inline_offset, gboolean is_virtual_call)
7703 {
7704         MonoError error;
7705         MonoInst *ins, **sp, **stack_start;
7706         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7707         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7708         MonoMethod *cmethod, *method_definition;
7709         MonoInst **arg_array;
7710         MonoMethodHeader *header;
7711         MonoImage *image;
7712         guint32 token, ins_flag;
7713         MonoClass *klass;
7714         MonoClass *constrained_class = NULL;
7715         unsigned char *ip, *end, *target, *err_pos;
7716         MonoMethodSignature *sig;
7717         MonoGenericContext *generic_context = NULL;
7718         MonoGenericContainer *generic_container = NULL;
7719         MonoType **param_types;
7720         int i, n, start_new_bblock, dreg;
7721         int num_calls = 0, inline_costs = 0;
7722         int breakpoint_id = 0;
7723         guint num_args;
7724         MonoBoolean security, pinvoke;
7725         MonoSecurityManager* secman = NULL;
7726         MonoDeclSecurityActions actions;
7727         GSList *class_inits = NULL;
7728         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7729         int context_used;
7730         gboolean init_locals, seq_points, skip_dead_blocks;
7731         gboolean sym_seq_points = FALSE;
7732         MonoInst *cached_tls_addr = NULL;
7733         MonoDebugMethodInfo *minfo;
7734         MonoBitSet *seq_point_locs = NULL;
7735         MonoBitSet *seq_point_set_locs = NULL;
7736
7737         cfg->disable_inline = is_jit_optimizer_disabled (method);
7738
7739         /* serialization and xdomain stuff may need access to private fields and methods */
7740         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7741         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7742         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7743         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7744         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7745         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7746
7747         dont_verify |= mono_security_smcs_hack_enabled ();
7748
7749         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7750         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7751         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7752         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7753         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7754
7755         image = method->klass->image;
7756         header = mono_method_get_header (method);
7757         if (!header) {
7758                 MonoLoaderError *error;
7759
7760                 if ((error = mono_loader_get_last_error ())) {
7761                         mono_cfg_set_exception (cfg, error->exception_type);
7762                 } else {
7763                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7764                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7765                 }
7766                 goto exception_exit;
7767         }
7768         generic_container = mono_method_get_generic_container (method);
7769         sig = mono_method_signature (method);
7770         num_args = sig->hasthis + sig->param_count;
7771         ip = (unsigned char*)header->code;
7772         cfg->cil_start = ip;
7773         end = ip + header->code_size;
7774         cfg->stat_cil_code_size += header->code_size;
7775
7776         seq_points = cfg->gen_seq_points && cfg->method == method;
7777 #ifdef PLATFORM_ANDROID
7778         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7779 #endif
7780
7781         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7782                 /* We could hit a seq point before attaching to the JIT (#8338) */
7783                 seq_points = FALSE;
7784         }
7785
7786         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7787                 minfo = mono_debug_lookup_method (method);
7788                 if (minfo) {
7789                         int i, n_il_offsets;
7790                         int *il_offsets;
7791                         int *line_numbers;
7792
7793                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7794                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7795                         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);
7796                         sym_seq_points = TRUE;
7797                         for (i = 0; i < n_il_offsets; ++i) {
7798                                 if (il_offsets [i] < header->code_size)
7799                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7800                         }
7801                         g_free (il_offsets);
7802                         g_free (line_numbers);
7803                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7804                         /* Methods without line number info like auto-generated property accessors */
7805                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7806                         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);
7807                         sym_seq_points = TRUE;
7808                 }
7809         }
7810
7811         /* 
7812          * Methods without init_locals set could cause asserts in various passes
7813          * (#497220). To work around this, we emit dummy initialization opcodes
7814          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7815          * on some platforms.
7816          */
7817         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7818                 init_locals = header->init_locals;
7819         else
7820                 init_locals = TRUE;
7821
7822         method_definition = method;
7823         while (method_definition->is_inflated) {
7824                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7825                 method_definition = imethod->declaring;
7826         }
7827
7828         /* SkipVerification is not allowed if core-clr is enabled */
7829         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7830                 dont_verify = TRUE;
7831                 dont_verify_stloc = TRUE;
7832         }
7833
7834         if (sig->is_inflated)
7835                 generic_context = mono_method_get_context (method);
7836         else if (generic_container)
7837                 generic_context = &generic_container->context;
7838         cfg->generic_context = generic_context;
7839
7840         if (!cfg->generic_sharing_context)
7841                 g_assert (!sig->has_type_parameters);
7842
7843         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7844                 g_assert (method->is_inflated);
7845                 g_assert (mono_method_get_context (method)->method_inst);
7846         }
7847         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7848                 g_assert (sig->generic_param_count);
7849
7850         if (cfg->method == method) {
7851                 cfg->real_offset = 0;
7852         } else {
7853                 cfg->real_offset = inline_offset;
7854         }
7855
7856         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7857         cfg->cil_offset_to_bb_len = header->code_size;
7858
7859         cfg->current_method = method;
7860
7861         if (cfg->verbose_level > 2)
7862                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7863
7864         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7865         if (sig->hasthis)
7866                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7867         for (n = 0; n < sig->param_count; ++n)
7868                 param_types [n + sig->hasthis] = sig->params [n];
7869         cfg->arg_types = param_types;
7870
7871         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7872         if (cfg->method == method) {
7873
7874                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7875                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7876
7877                 /* ENTRY BLOCK */
7878                 NEW_BBLOCK (cfg, start_bblock);
7879                 cfg->bb_entry = start_bblock;
7880                 start_bblock->cil_code = NULL;
7881                 start_bblock->cil_length = 0;
7882 #if defined(__native_client_codegen__)
7883                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7884                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7885                 MONO_ADD_INS (start_bblock, ins);
7886 #endif
7887
7888                 /* EXIT BLOCK */
7889                 NEW_BBLOCK (cfg, end_bblock);
7890                 cfg->bb_exit = end_bblock;
7891                 end_bblock->cil_code = NULL;
7892                 end_bblock->cil_length = 0;
7893                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7894                 g_assert (cfg->num_bblocks == 2);
7895
7896                 arg_array = cfg->args;
7897
7898                 if (header->num_clauses) {
7899                         cfg->spvars = g_hash_table_new (NULL, NULL);
7900                         cfg->exvars = g_hash_table_new (NULL, NULL);
7901                 }
7902                 /* handle exception clauses */
7903                 for (i = 0; i < header->num_clauses; ++i) {
7904                         MonoBasicBlock *try_bb;
7905                         MonoExceptionClause *clause = &header->clauses [i];
7906                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7907                         try_bb->real_offset = clause->try_offset;
7908                         try_bb->try_start = TRUE;
7909                         try_bb->region = ((i + 1) << 8) | clause->flags;
7910                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7911                         tblock->real_offset = clause->handler_offset;
7912                         tblock->flags |= BB_EXCEPTION_HANDLER;
7913
7914                         /*
7915                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7916                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7917                          */
7918                         if (COMPILE_LLVM (cfg))
7919                                 link_bblock (cfg, try_bb, tblock);
7920
7921                         if (*(ip + clause->handler_offset) == CEE_POP)
7922                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7923
7924                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7925                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7926                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7927                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7928                                 MONO_ADD_INS (tblock, ins);
7929
7930                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7931                                         /* finally clauses already have a seq point */
7932                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7933                                         MONO_ADD_INS (tblock, ins);
7934                                 }
7935
7936                                 /* todo: is a fault block unsafe to optimize? */
7937                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7938                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7939                         }
7940
7941
7942                         /*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);
7943                           while (p < end) {
7944                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7945                           }*/
7946                         /* catch and filter blocks get the exception object on the stack */
7947                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7948                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7949                                 MonoInst *dummy_use;
7950
7951                                 /* mostly like handle_stack_args (), but just sets the input args */
7952                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7953                                 tblock->in_scount = 1;
7954                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7955                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7956
7957                                 /* 
7958                                  * Add a dummy use for the exvar so its liveness info will be
7959                                  * correct.
7960                                  */
7961                                 cfg->cbb = tblock;
7962                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7963                                 
7964                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7965                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7966                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7967                                         tblock->real_offset = clause->data.filter_offset;
7968                                         tblock->in_scount = 1;
7969                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7970                                         /* The filter block shares the exvar with the handler block */
7971                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7972                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7973                                         MONO_ADD_INS (tblock, ins);
7974                                 }
7975                         }
7976
7977                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7978                                         clause->data.catch_class &&
7979                                         cfg->generic_sharing_context &&
7980                                         mono_class_check_context_used (clause->data.catch_class)) {
7981                                 /*
7982                                  * In shared generic code with catch
7983                                  * clauses containing type variables
7984                                  * the exception handling code has to
7985                                  * be able to get to the rgctx.
7986                                  * Therefore we have to make sure that
7987                                  * the vtable/mrgctx argument (for
7988                                  * static or generic methods) or the
7989                                  * "this" argument (for non-static
7990                                  * methods) are live.
7991                                  */
7992                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7993                                                 mini_method_get_context (method)->method_inst ||
7994                                                 method->klass->valuetype) {
7995                                         mono_get_vtable_var (cfg);
7996                                 } else {
7997                                         MonoInst *dummy_use;
7998
7999                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8000                                 }
8001                         }
8002                 }
8003         } else {
8004                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8005                 cfg->cbb = start_bblock;
8006                 cfg->args = arg_array;
8007                 mono_save_args (cfg, sig, inline_args);
8008         }
8009
8010         /* FIRST CODE BLOCK */
8011         NEW_BBLOCK (cfg, bblock);
8012         bblock->cil_code = ip;
8013         cfg->cbb = bblock;
8014         cfg->ip = ip;
8015
8016         ADD_BBLOCK (cfg, bblock);
8017
8018         if (cfg->method == method) {
8019                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8020                 if (breakpoint_id) {
8021                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8022                         MONO_ADD_INS (bblock, ins);
8023                 }
8024         }
8025
8026         if (mono_security_cas_enabled ())
8027                 secman = mono_security_manager_get_methods ();
8028
8029         security = (secman && mono_security_method_has_declsec (method));
8030         /* at this point having security doesn't mean we have any code to generate */
8031         if (security && (cfg->method == method)) {
8032                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
8033                  * And we do not want to enter the next section (with allocation) if we
8034                  * have nothing to generate */
8035                 security = mono_declsec_get_demands (method, &actions);
8036         }
8037
8038         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
8039         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
8040         if (pinvoke) {
8041                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8042                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8043                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
8044
8045                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
8046                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8047                                 pinvoke = FALSE;
8048                         }
8049                         if (custom)
8050                                 mono_custom_attrs_free (custom);
8051
8052                         if (pinvoke) {
8053                                 custom = mono_custom_attrs_from_class (wrapped->klass);
8054                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
8055                                         pinvoke = FALSE;
8056                                 }
8057                                 if (custom)
8058                                         mono_custom_attrs_free (custom);
8059                         }
8060                 } else {
8061                         /* not a P/Invoke after all */
8062                         pinvoke = FALSE;
8063                 }
8064         }
8065         
8066         /* we use a separate basic block for the initialization code */
8067         NEW_BBLOCK (cfg, init_localsbb);
8068         cfg->bb_init = init_localsbb;
8069         init_localsbb->real_offset = cfg->real_offset;
8070         start_bblock->next_bb = init_localsbb;
8071         init_localsbb->next_bb = bblock;
8072         link_bblock (cfg, start_bblock, init_localsbb);
8073         link_bblock (cfg, init_localsbb, bblock);
8074                 
8075         cfg->cbb = init_localsbb;
8076
8077         if (cfg->gsharedvt && cfg->method == method) {
8078                 MonoGSharedVtMethodInfo *info;
8079                 MonoInst *var, *locals_var;
8080                 int dreg;
8081
8082                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8083                 info->method = cfg->method;
8084                 info->count_entries = 16;
8085                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8086                 cfg->gsharedvt_info = info;
8087
8088                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8089                 /* prevent it from being register allocated */
8090                 //var->flags |= MONO_INST_VOLATILE;
8091                 cfg->gsharedvt_info_var = var;
8092
8093                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8094                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8095
8096                 /* Allocate locals */
8097                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8098                 /* prevent it from being register allocated */
8099                 //locals_var->flags |= MONO_INST_VOLATILE;
8100                 cfg->gsharedvt_locals_var = locals_var;
8101
8102                 dreg = alloc_ireg (cfg);
8103                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8104
8105                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8106                 ins->dreg = locals_var->dreg;
8107                 ins->sreg1 = dreg;
8108                 MONO_ADD_INS (cfg->cbb, ins);
8109                 cfg->gsharedvt_locals_var_ins = ins;
8110                 
8111                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8112                 /*
8113                 if (init_locals)
8114                         ins->flags |= MONO_INST_INIT;
8115                 */
8116         }
8117
8118         /* at this point we know, if security is TRUE, that some code needs to be generated */
8119         if (security && (cfg->method == method)) {
8120                 MonoInst *args [2];
8121
8122                 cfg->stat_cas_demand_generation++;
8123
8124                 if (actions.demand.blob) {
8125                         /* Add code for SecurityAction.Demand */
8126                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
8127                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
8128                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8129                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8130                 }
8131                 if (actions.noncasdemand.blob) {
8132                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
8133                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
8134                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
8135                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
8136                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
8137                         mono_emit_method_call (cfg, secman->demand, args, NULL);
8138                 }
8139                 if (actions.demandchoice.blob) {
8140                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
8141                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
8142                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
8143                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
8144                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
8145                 }
8146         }
8147
8148         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
8149         if (pinvoke) {
8150                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
8151         }
8152
8153         if (mono_security_core_clr_enabled ()) {
8154                 /* check if this is native code, e.g. an icall or a p/invoke */
8155                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8156                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8157                         if (wrapped) {
8158                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8159                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8160
8161                                 /* if this ia a native call then it can only be JITted from platform code */
8162                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8163                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8164                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8165                                                         mono_get_exception_method_access ();
8166                                                 emit_throw_exception (cfg, ex);
8167                                         }
8168                                 }
8169                         }
8170                 }
8171         }
8172
8173         CHECK_CFG_EXCEPTION;
8174
8175         if (header->code_size == 0)
8176                 UNVERIFIED;
8177
8178         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8179                 ip = err_pos;
8180                 UNVERIFIED;
8181         }
8182
8183         if (cfg->method == method)
8184                 mono_debug_init_method (cfg, bblock, breakpoint_id);
8185
8186         for (n = 0; n < header->num_locals; ++n) {
8187                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8188                         UNVERIFIED;
8189         }
8190         class_inits = NULL;
8191
8192         /* We force the vtable variable here for all shared methods
8193            for the possibility that they might show up in a stack
8194            trace where their exact instantiation is needed. */
8195         if (cfg->generic_sharing_context && method == cfg->method) {
8196                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8197                                 mini_method_get_context (method)->method_inst ||
8198                                 method->klass->valuetype) {
8199                         mono_get_vtable_var (cfg);
8200                 } else {
8201                         /* FIXME: Is there a better way to do this?
8202                            We need the variable live for the duration
8203                            of the whole method. */
8204                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8205                 }
8206         }
8207
8208         /* add a check for this != NULL to inlined methods */
8209         if (is_virtual_call) {
8210                 MonoInst *arg_ins;
8211
8212                 NEW_ARGLOAD (cfg, arg_ins, 0);
8213                 MONO_ADD_INS (cfg->cbb, arg_ins);
8214                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8215         }
8216
8217         skip_dead_blocks = !dont_verify;
8218         if (skip_dead_blocks) {
8219                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8220                 CHECK_CFG_ERROR;
8221                 g_assert (bb);
8222         }
8223
8224         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8225         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8226
8227         ins_flag = 0;
8228         start_new_bblock = 0;
8229         cfg->cbb = bblock;
8230         while (ip < end) {
8231                 if (cfg->method == method)
8232                         cfg->real_offset = ip - header->code;
8233                 else
8234                         cfg->real_offset = inline_offset;
8235                 cfg->ip = ip;
8236
8237                 context_used = 0;
8238                 
8239                 if (start_new_bblock) {
8240                         bblock->cil_length = ip - bblock->cil_code;
8241                         if (start_new_bblock == 2) {
8242                                 g_assert (ip == tblock->cil_code);
8243                         } else {
8244                                 GET_BBLOCK (cfg, tblock, ip);
8245                         }
8246                         bblock->next_bb = tblock;
8247                         bblock = tblock;
8248                         cfg->cbb = bblock;
8249                         start_new_bblock = 0;
8250                         for (i = 0; i < bblock->in_scount; ++i) {
8251                                 if (cfg->verbose_level > 3)
8252                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8253                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8254                                 *sp++ = ins;
8255                         }
8256                         if (class_inits)
8257                                 g_slist_free (class_inits);
8258                         class_inits = NULL;
8259                 } else {
8260                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
8261                                 link_bblock (cfg, bblock, tblock);
8262                                 if (sp != stack_start) {
8263                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8264                                         sp = stack_start;
8265                                         CHECK_UNVERIFIABLE (cfg);
8266                                 }
8267                                 bblock->next_bb = tblock;
8268                                 bblock = tblock;
8269                                 cfg->cbb = bblock;
8270                                 for (i = 0; i < bblock->in_scount; ++i) {
8271                                         if (cfg->verbose_level > 3)
8272                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
8273                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
8274                                         *sp++ = ins;
8275                                 }
8276                                 g_slist_free (class_inits);
8277                                 class_inits = NULL;
8278                         }
8279                 }
8280
8281                 if (skip_dead_blocks) {
8282                         int ip_offset = ip - header->code;
8283
8284                         if (ip_offset == bb->end)
8285                                 bb = bb->next;
8286
8287                         if (bb->dead) {
8288                                 int op_size = mono_opcode_size (ip, end);
8289                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8290
8291                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8292
8293                                 if (ip_offset + op_size == bb->end) {
8294                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8295                                         MONO_ADD_INS (bblock, ins);
8296                                         start_new_bblock = 1;
8297                                 }
8298
8299                                 ip += op_size;
8300                                 continue;
8301                         }
8302                 }
8303                 /*
8304                  * Sequence points are points where the debugger can place a breakpoint.
8305                  * Currently, we generate these automatically at points where the IL
8306                  * stack is empty.
8307                  */
8308                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8309                         /*
8310                          * Make methods interruptable at the beginning, and at the targets of
8311                          * backward branches.
8312                          * Also, do this at the start of every bblock in methods with clauses too,
8313                          * to be able to handle instructions with inprecise control flow like
8314                          * throw/endfinally.
8315                          * Backward branches are handled at the end of method-to-ir ().
8316                          */
8317                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8318
8319                         /* Avoid sequence points on empty IL like .volatile */
8320                         // FIXME: Enable this
8321                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8322                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8323                         if (sp != stack_start)
8324                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8325                         MONO_ADD_INS (cfg->cbb, ins);
8326
8327                         if (sym_seq_points)
8328                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8329                 }
8330
8331                 bblock->real_offset = cfg->real_offset;
8332
8333                 if ((cfg->method == method) && cfg->coverage_info) {
8334                         guint32 cil_offset = ip - header->code;
8335                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8336
8337                         /* TODO: Use an increment here */
8338 #if defined(TARGET_X86)
8339                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8340                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8341                         ins->inst_imm = 1;
8342                         MONO_ADD_INS (cfg->cbb, ins);
8343 #else
8344                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8345                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8346 #endif
8347                 }
8348
8349                 if (cfg->verbose_level > 3)
8350                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8351
8352                 switch (*ip) {
8353                 case CEE_NOP:
8354                         if (seq_points && !sym_seq_points && sp != stack_start) {
8355                                 /*
8356                                  * The C# compiler uses these nops to notify the JIT that it should
8357                                  * insert seq points.
8358                                  */
8359                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8360                                 MONO_ADD_INS (cfg->cbb, ins);
8361                         }
8362                         if (cfg->keep_cil_nops)
8363                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8364                         else
8365                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8366                         ip++;
8367                         MONO_ADD_INS (bblock, ins);
8368                         break;
8369                 case CEE_BREAK:
8370                         if (should_insert_brekpoint (cfg->method)) {
8371                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8372                         } else {
8373                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8374                         }
8375                         ip++;
8376                         MONO_ADD_INS (bblock, ins);
8377                         break;
8378                 case CEE_LDARG_0:
8379                 case CEE_LDARG_1:
8380                 case CEE_LDARG_2:
8381                 case CEE_LDARG_3:
8382                         CHECK_STACK_OVF (1);
8383                         n = (*ip)-CEE_LDARG_0;
8384                         CHECK_ARG (n);
8385                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8386                         ip++;
8387                         *sp++ = ins;
8388                         break;
8389                 case CEE_LDLOC_0:
8390                 case CEE_LDLOC_1:
8391                 case CEE_LDLOC_2:
8392                 case CEE_LDLOC_3:
8393                         CHECK_STACK_OVF (1);
8394                         n = (*ip)-CEE_LDLOC_0;
8395                         CHECK_LOCAL (n);
8396                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8397                         ip++;
8398                         *sp++ = ins;
8399                         break;
8400                 case CEE_STLOC_0:
8401                 case CEE_STLOC_1:
8402                 case CEE_STLOC_2:
8403                 case CEE_STLOC_3: {
8404                         CHECK_STACK (1);
8405                         n = (*ip)-CEE_STLOC_0;
8406                         CHECK_LOCAL (n);
8407                         --sp;
8408                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8409                                 UNVERIFIED;
8410                         emit_stloc_ir (cfg, sp, header, n);
8411                         ++ip;
8412                         inline_costs += 1;
8413                         break;
8414                         }
8415                 case CEE_LDARG_S:
8416                         CHECK_OPSIZE (2);
8417                         CHECK_STACK_OVF (1);
8418                         n = ip [1];
8419                         CHECK_ARG (n);
8420                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8421                         *sp++ = ins;
8422                         ip += 2;
8423                         break;
8424                 case CEE_LDARGA_S:
8425                         CHECK_OPSIZE (2);
8426                         CHECK_STACK_OVF (1);
8427                         n = ip [1];
8428                         CHECK_ARG (n);
8429                         NEW_ARGLOADA (cfg, ins, n);
8430                         MONO_ADD_INS (cfg->cbb, ins);
8431                         *sp++ = ins;
8432                         ip += 2;
8433                         break;
8434                 case CEE_STARG_S:
8435                         CHECK_OPSIZE (2);
8436                         CHECK_STACK (1);
8437                         --sp;
8438                         n = ip [1];
8439                         CHECK_ARG (n);
8440                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8441                                 UNVERIFIED;
8442                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8443                         ip += 2;
8444                         break;
8445                 case CEE_LDLOC_S:
8446                         CHECK_OPSIZE (2);
8447                         CHECK_STACK_OVF (1);
8448                         n = ip [1];
8449                         CHECK_LOCAL (n);
8450                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8451                         *sp++ = ins;
8452                         ip += 2;
8453                         break;
8454                 case CEE_LDLOCA_S: {
8455                         unsigned char *tmp_ip;
8456                         CHECK_OPSIZE (2);
8457                         CHECK_STACK_OVF (1);
8458                         CHECK_LOCAL (ip [1]);
8459
8460                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8461                                 ip = tmp_ip;
8462                                 inline_costs += 1;
8463                                 break;
8464                         }
8465
8466                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8467                         *sp++ = ins;
8468                         ip += 2;
8469                         break;
8470                 }
8471                 case CEE_STLOC_S:
8472                         CHECK_OPSIZE (2);
8473                         CHECK_STACK (1);
8474                         --sp;
8475                         CHECK_LOCAL (ip [1]);
8476                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8477                                 UNVERIFIED;
8478                         emit_stloc_ir (cfg, sp, header, ip [1]);
8479                         ip += 2;
8480                         inline_costs += 1;
8481                         break;
8482                 case CEE_LDNULL:
8483                         CHECK_STACK_OVF (1);
8484                         EMIT_NEW_PCONST (cfg, ins, NULL);
8485                         ins->type = STACK_OBJ;
8486                         ++ip;
8487                         *sp++ = ins;
8488                         break;
8489                 case CEE_LDC_I4_M1:
8490                         CHECK_STACK_OVF (1);
8491                         EMIT_NEW_ICONST (cfg, ins, -1);
8492                         ++ip;
8493                         *sp++ = ins;
8494                         break;
8495                 case CEE_LDC_I4_0:
8496                 case CEE_LDC_I4_1:
8497                 case CEE_LDC_I4_2:
8498                 case CEE_LDC_I4_3:
8499                 case CEE_LDC_I4_4:
8500                 case CEE_LDC_I4_5:
8501                 case CEE_LDC_I4_6:
8502                 case CEE_LDC_I4_7:
8503                 case CEE_LDC_I4_8:
8504                         CHECK_STACK_OVF (1);
8505                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8506                         ++ip;
8507                         *sp++ = ins;
8508                         break;
8509                 case CEE_LDC_I4_S:
8510                         CHECK_OPSIZE (2);
8511                         CHECK_STACK_OVF (1);
8512                         ++ip;
8513                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8514                         ++ip;
8515                         *sp++ = ins;
8516                         break;
8517                 case CEE_LDC_I4:
8518                         CHECK_OPSIZE (5);
8519                         CHECK_STACK_OVF (1);
8520                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8521                         ip += 5;
8522                         *sp++ = ins;
8523                         break;
8524                 case CEE_LDC_I8:
8525                         CHECK_OPSIZE (9);
8526                         CHECK_STACK_OVF (1);
8527                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8528                         ins->type = STACK_I8;
8529                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8530                         ++ip;
8531                         ins->inst_l = (gint64)read64 (ip);
8532                         MONO_ADD_INS (bblock, ins);
8533                         ip += 8;
8534                         *sp++ = ins;
8535                         break;
8536                 case CEE_LDC_R4: {
8537                         float *f;
8538                         gboolean use_aotconst = FALSE;
8539
8540 #ifdef TARGET_POWERPC
8541                         /* FIXME: Clean this up */
8542                         if (cfg->compile_aot)
8543                                 use_aotconst = TRUE;
8544 #endif
8545
8546                         /* FIXME: we should really allocate this only late in the compilation process */
8547                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8548                         CHECK_OPSIZE (5);
8549                         CHECK_STACK_OVF (1);
8550
8551                         if (use_aotconst) {
8552                                 MonoInst *cons;
8553                                 int dreg;
8554
8555                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8556
8557                                 dreg = alloc_freg (cfg);
8558                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8559                                 ins->type = cfg->r4_stack_type;
8560                         } else {
8561                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8562                                 ins->type = cfg->r4_stack_type;
8563                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8564                                 ins->inst_p0 = f;
8565                                 MONO_ADD_INS (bblock, ins);
8566                         }
8567                         ++ip;
8568                         readr4 (ip, f);
8569                         ip += 4;
8570                         *sp++ = ins;                    
8571                         break;
8572                 }
8573                 case CEE_LDC_R8: {
8574                         double *d;
8575                         gboolean use_aotconst = FALSE;
8576
8577 #ifdef TARGET_POWERPC
8578                         /* FIXME: Clean this up */
8579                         if (cfg->compile_aot)
8580                                 use_aotconst = TRUE;
8581 #endif
8582
8583                         /* FIXME: we should really allocate this only late in the compilation process */
8584                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8585                         CHECK_OPSIZE (9);
8586                         CHECK_STACK_OVF (1);
8587
8588                         if (use_aotconst) {
8589                                 MonoInst *cons;
8590                                 int dreg;
8591
8592                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8593
8594                                 dreg = alloc_freg (cfg);
8595                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8596                                 ins->type = STACK_R8;
8597                         } else {
8598                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8599                                 ins->type = STACK_R8;
8600                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8601                                 ins->inst_p0 = d;
8602                                 MONO_ADD_INS (bblock, ins);
8603                         }
8604                         ++ip;
8605                         readr8 (ip, d);
8606                         ip += 8;
8607                         *sp++ = ins;
8608                         break;
8609                 }
8610                 case CEE_DUP: {
8611                         MonoInst *temp, *store;
8612                         CHECK_STACK (1);
8613                         CHECK_STACK_OVF (1);
8614                         sp--;
8615                         ins = *sp;
8616
8617                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8618                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8619
8620                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8621                         *sp++ = ins;
8622
8623                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8624                         *sp++ = ins;
8625
8626                         ++ip;
8627                         inline_costs += 2;
8628                         break;
8629                 }
8630                 case CEE_POP:
8631                         CHECK_STACK (1);
8632                         ip++;
8633                         --sp;
8634
8635 #ifdef TARGET_X86
8636                         if (sp [0]->type == STACK_R8)
8637                                 /* we need to pop the value from the x86 FP stack */
8638                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8639 #endif
8640                         break;
8641                 case CEE_JMP: {
8642                         MonoCallInst *call;
8643
8644                         INLINE_FAILURE ("jmp");
8645                         GSHAREDVT_FAILURE (*ip);
8646
8647                         CHECK_OPSIZE (5);
8648                         if (stack_start != sp)
8649                                 UNVERIFIED;
8650                         token = read32 (ip + 1);
8651                         /* FIXME: check the signature matches */
8652                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8653
8654                         if (!cmethod || mono_loader_get_last_error ())
8655                                 LOAD_ERROR;
8656  
8657                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8658                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8659
8660                         if (mono_security_cas_enabled ())
8661                                 CHECK_CFG_EXCEPTION;
8662
8663                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8664
8665                         if (ARCH_HAVE_OP_TAIL_CALL) {
8666                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8667                                 int i, n;
8668
8669                                 /* Handle tail calls similarly to calls */
8670                                 n = fsig->param_count + fsig->hasthis;
8671
8672                                 DISABLE_AOT (cfg);
8673
8674                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8675                                 call->method = cmethod;
8676                                 call->tail_call = TRUE;
8677                                 call->signature = mono_method_signature (cmethod);
8678                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8679                                 call->inst.inst_p0 = cmethod;
8680                                 for (i = 0; i < n; ++i)
8681                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8682
8683                                 mono_arch_emit_call (cfg, call);
8684                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8685                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8686                         } else {
8687                                 for (i = 0; i < num_args; ++i)
8688                                         /* Prevent arguments from being optimized away */
8689                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8690
8691                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8692                                 ins = (MonoInst*)call;
8693                                 ins->inst_p0 = cmethod;
8694                                 MONO_ADD_INS (bblock, ins);
8695                         }
8696
8697                         ip += 5;
8698                         start_new_bblock = 1;
8699                         break;
8700                 }
8701                 case CEE_CALLI:
8702                 case CEE_CALL:
8703                 case CEE_CALLVIRT: {
8704                         MonoInst *addr = NULL;
8705                         MonoMethodSignature *fsig = NULL;
8706                         int array_rank = 0;
8707                         int virtual = *ip == CEE_CALLVIRT;
8708                         int calli = *ip == CEE_CALLI;
8709                         gboolean pass_imt_from_rgctx = FALSE;
8710                         MonoInst *imt_arg = NULL;
8711                         MonoInst *keep_this_alive = NULL;
8712                         gboolean pass_vtable = FALSE;
8713                         gboolean pass_mrgctx = FALSE;
8714                         MonoInst *vtable_arg = NULL;
8715                         gboolean check_this = FALSE;
8716                         gboolean supported_tail_call = FALSE;
8717                         gboolean tail_call = FALSE;
8718                         gboolean need_seq_point = FALSE;
8719                         guint32 call_opcode = *ip;
8720                         gboolean emit_widen = TRUE;
8721                         gboolean push_res = TRUE;
8722                         gboolean skip_ret = FALSE;
8723                         gboolean delegate_invoke = FALSE;
8724
8725                         CHECK_OPSIZE (5);
8726                         token = read32 (ip + 1);
8727
8728                         ins = NULL;
8729
8730                         if (calli) {
8731                                 //GSHAREDVT_FAILURE (*ip);
8732                                 cmethod = NULL;
8733                                 CHECK_STACK (1);
8734                                 --sp;
8735                                 addr = *sp;
8736                                 fsig = mini_get_signature (method, token, generic_context);
8737                                 n = fsig->param_count + fsig->hasthis;
8738
8739                                 if (method->dynamic && fsig->pinvoke) {
8740                                         MonoInst *args [3];
8741
8742                                         /*
8743                                          * This is a call through a function pointer using a pinvoke
8744                                          * signature. Have to create a wrapper and call that instead.
8745                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8746                                          * instead based on the signature.
8747                                          */
8748                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8749                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8750                                         args [2] = addr;
8751                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8752                                 }
8753                         } else {
8754                                 MonoMethod *cil_method;
8755
8756                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8757                                 cil_method = cmethod;
8758                                 
8759                                 if (constrained_class) {
8760                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8761                                                 if (cfg->verbose_level > 2)
8762                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8763                                                 if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8764                                                            constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8765                                                           cfg->generic_sharing_context)) {
8766                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8767                                                         CHECK_CFG_ERROR;
8768                                                 }
8769                                         } else {
8770                                                 if (cfg->verbose_level > 2)
8771                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8772
8773                                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8774                                                         /* 
8775                                                          * This is needed since get_method_constrained can't find 
8776                                                          * the method in klass representing a type var.
8777                                                          * The type var is guaranteed to be a reference type in this
8778                                                          * case.
8779                                                          */
8780                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_class))
8781                                                                 g_assert (!cmethod->klass->valuetype);
8782                                                 } else {
8783                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8784                                                         CHECK_CFG_ERROR;
8785                                                 }
8786                                         }
8787                                 }
8788                                         
8789                                 if (!cmethod || mono_loader_get_last_error ())
8790                                         LOAD_ERROR;
8791                                 if (!dont_verify && !cfg->skip_visibility) {
8792                                         MonoMethod *target_method = cil_method;
8793                                         if (method->is_inflated) {
8794                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8795                                         }
8796                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8797                                                 !mono_method_can_access_method (method, cil_method))
8798                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8799                                 }
8800
8801                                 if (mono_security_core_clr_enabled ())
8802                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8803
8804                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8805                                         /* MS.NET seems to silently convert this to a callvirt */
8806                                         virtual = 1;
8807
8808                                 {
8809                                         /*
8810                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8811                                          * converts to a callvirt.
8812                                          *
8813                                          * tests/bug-515884.il is an example of this behavior
8814                                          */
8815                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8816                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8817                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8818                                                 virtual = 1;
8819                                 }
8820
8821                                 if (!cmethod->klass->inited)
8822                                         if (!mono_class_init (cmethod->klass))
8823                                                 TYPE_LOAD_ERROR (cmethod->klass);
8824
8825                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8826                                     mini_class_is_system_array (cmethod->klass)) {
8827                                         array_rank = cmethod->klass->rank;
8828                                         fsig = mono_method_signature (cmethod);
8829                                 } else {
8830                                         fsig = mono_method_signature (cmethod);
8831
8832                                         if (!fsig)
8833                                                 LOAD_ERROR;
8834
8835                                         if (fsig->pinvoke) {
8836                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8837                                                         check_for_pending_exc, cfg->compile_aot);
8838                                                 fsig = mono_method_signature (wrapper);
8839                                         } else if (constrained_class) {
8840                                                 fsig = mono_method_signature (cmethod);
8841                                         } else {
8842                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8843                                                 CHECK_CFG_ERROR;
8844                                         }
8845                                 }
8846
8847                                 mono_save_token_info (cfg, image, token, cil_method);
8848
8849                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8850                                         need_seq_point = TRUE;
8851
8852                                 n = fsig->param_count + fsig->hasthis;
8853
8854                                 /* Don't support calls made using type arguments for now */
8855                                 /*
8856                                 if (cfg->gsharedvt) {
8857                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8858                                                 GSHAREDVT_FAILURE (*ip);
8859                                 }
8860                                 */
8861
8862                                 if (mono_security_cas_enabled ()) {
8863                                         if (check_linkdemand (cfg, method, cmethod))
8864                                                 INLINE_FAILURE ("linkdemand");
8865                                         CHECK_CFG_EXCEPTION;
8866                                 }
8867
8868                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8869                                         g_assert_not_reached ();
8870                         }
8871
8872                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8873                                 UNVERIFIED;
8874
8875                         if (!cfg->generic_sharing_context && cmethod)
8876                                 g_assert (!mono_method_check_context_used (cmethod));
8877
8878                         CHECK_STACK (n);
8879
8880                         //g_assert (!virtual || fsig->hasthis);
8881
8882                         sp -= n;
8883
8884                         if (constrained_class) {
8885                                 if (mini_is_gsharedvt_klass (cfg, constrained_class)) {
8886                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
8887                                                 /* The 'Own method' case below */
8888                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8889                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8890                                         } else {
8891                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen, &bblock);
8892                                                 CHECK_CFG_EXCEPTION;
8893                                                 g_assert (ins);
8894                                                 goto call_end;
8895                                         }
8896                                 }
8897
8898                                 /*
8899                                  * We have the `constrained.' prefix opcode.
8900                                  */
8901                                 if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8902                                         /*
8903                                          * The type parameter is instantiated as a valuetype,
8904                                          * but that type doesn't override the method we're
8905                                          * calling, so we need to box `this'.
8906                                          */
8907                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8908                                         ins->klass = constrained_class;
8909                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
8910                                         CHECK_CFG_EXCEPTION;
8911                                 } else if (!constrained_class->valuetype) {
8912                                         int dreg = alloc_ireg_ref (cfg);
8913
8914                                         /*
8915                                          * The type parameter is instantiated as a reference
8916                                          * type.  We have a managed pointer on the stack, so
8917                                          * we need to dereference it here.
8918                                          */
8919                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8920                                         ins->type = STACK_OBJ;
8921                                         sp [0] = ins;
8922                                 } else {
8923                                         if (cmethod->klass->valuetype) {
8924                                                 /* Own method */
8925                                         } else {
8926                                                 /* Interface method */
8927                                                 int ioffset, slot;
8928
8929                                                 mono_class_setup_vtable (constrained_class);
8930                                                 CHECK_TYPELOAD (constrained_class);
8931                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
8932                                                 if (ioffset == -1)
8933                                                         TYPE_LOAD_ERROR (constrained_class);
8934                                                 slot = mono_method_get_vtable_slot (cmethod);
8935                                                 if (slot == -1)
8936                                                         TYPE_LOAD_ERROR (cmethod->klass);
8937                                                 cmethod = constrained_class->vtable [ioffset + slot];
8938
8939                                                 if (cmethod->klass == mono_defaults.enum_class) {
8940                                                         /* Enum implements some interfaces, so treat this as the first case */
8941                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
8942                                                         ins->klass = constrained_class;
8943                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class), &bblock);
8944                                                         CHECK_CFG_EXCEPTION;
8945                                                 }
8946                                         }
8947                                         virtual = 0;
8948                                 }
8949                                 constrained_class = NULL;
8950                         }
8951
8952                         if (!calli && check_call_signature (cfg, fsig, sp))
8953                                 UNVERIFIED;
8954
8955 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8956                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8957                                 delegate_invoke = TRUE;
8958 #endif
8959
8960                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8961                                 bblock = cfg->cbb;
8962                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8963                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8964                                         emit_widen = FALSE;
8965                                 }
8966
8967                                 goto call_end;
8968                         }
8969
8970                         /* 
8971                          * If the callee is a shared method, then its static cctor
8972                          * might not get called after the call was patched.
8973                          */
8974                         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)) {
8975                                 emit_generic_class_init (cfg, cmethod->klass);
8976                                 CHECK_TYPELOAD (cmethod->klass);
8977                         }
8978
8979                         if (cmethod)
8980                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8981
8982                         if (cfg->generic_sharing_context && cmethod) {
8983                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8984
8985                                 context_used = mini_method_check_context_used (cfg, cmethod);
8986
8987                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8988                                         /* Generic method interface
8989                                            calls are resolved via a
8990                                            helper function and don't
8991                                            need an imt. */
8992                                         if (!cmethod_context || !cmethod_context->method_inst)
8993                                                 pass_imt_from_rgctx = TRUE;
8994                                 }
8995
8996                                 /*
8997                                  * If a shared method calls another
8998                                  * shared method then the caller must
8999                                  * have a generic sharing context
9000                                  * because the magic trampoline
9001                                  * requires it.  FIXME: We shouldn't
9002                                  * have to force the vtable/mrgctx
9003                                  * variable here.  Instead there
9004                                  * should be a flag in the cfg to
9005                                  * request a generic sharing context.
9006                                  */
9007                                 if (context_used &&
9008                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9009                                         mono_get_vtable_var (cfg);
9010                         }
9011
9012                         if (pass_vtable) {
9013                                 if (context_used) {
9014                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9015                                 } else {
9016                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9017
9018                                         CHECK_TYPELOAD (cmethod->klass);
9019                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9020                                 }
9021                         }
9022
9023                         if (pass_mrgctx) {
9024                                 g_assert (!vtable_arg);
9025
9026                                 if (!cfg->compile_aot) {
9027                                         /* 
9028                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9029                                          * for type load errors before.
9030                                          */
9031                                         mono_class_setup_vtable (cmethod->klass);
9032                                         CHECK_TYPELOAD (cmethod->klass);
9033                                 }
9034
9035                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9036
9037                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9038                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9039                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9040                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9041                                         if (virtual)
9042                                                 check_this = TRUE;
9043                                         virtual = 0;
9044                                 }
9045                         }
9046
9047                         if (pass_imt_from_rgctx) {
9048                                 g_assert (!pass_vtable);
9049                                 g_assert (cmethod);
9050
9051                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9052                                         cmethod, MONO_RGCTX_INFO_METHOD);
9053                         }
9054
9055                         if (check_this)
9056                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9057
9058                         /* Calling virtual generic methods */
9059                         if (cmethod && virtual && 
9060                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
9061                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9062                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9063                             fsig->generic_param_count && 
9064                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
9065                                 MonoInst *this_temp, *this_arg_temp, *store;
9066                                 MonoInst *iargs [4];
9067                                 gboolean use_imt = FALSE;
9068
9069                                 g_assert (fsig->is_inflated);
9070
9071                                 /* Prevent inlining of methods that contain indirect calls */
9072                                 INLINE_FAILURE ("virtual generic call");
9073
9074                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9075                                         GSHAREDVT_FAILURE (*ip);
9076
9077 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
9078                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
9079                                         use_imt = TRUE;
9080 #endif
9081
9082                                 if (use_imt) {
9083                                         g_assert (!imt_arg);
9084                                         if (!context_used)
9085                                                 g_assert (cmethod->is_inflated);
9086                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9087                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9088                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9089                                 } else {
9090                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9091                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9092                                         MONO_ADD_INS (bblock, store);
9093
9094                                         /* FIXME: This should be a managed pointer */
9095                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9096
9097                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9098                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9099                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9100                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9101                                         addr = mono_emit_jit_icall (cfg,
9102                                                                                                 mono_helper_compile_generic_method, iargs);
9103
9104                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9105
9106                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9107                                 }
9108
9109                                 goto call_end;
9110                         }
9111
9112                         /*
9113                          * Implement a workaround for the inherent races involved in locking:
9114                          * Monitor.Enter ()
9115                          * try {
9116                          * } finally {
9117                          *    Monitor.Exit ()
9118                          * }
9119                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9120                          * try block, the Exit () won't be executed, see:
9121                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9122                          * To work around this, we extend such try blocks to include the last x bytes
9123                          * of the Monitor.Enter () call.
9124                          */
9125                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9126                                 MonoBasicBlock *tbb;
9127
9128                                 GET_BBLOCK (cfg, tbb, ip + 5);
9129                                 /* 
9130                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9131                                  * from Monitor.Enter like ArgumentNullException.
9132                                  */
9133                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9134                                         /* Mark this bblock as needing to be extended */
9135                                         tbb->extend_try_block = TRUE;
9136                                 }
9137                         }
9138
9139                         /* Conversion to a JIT intrinsic */
9140                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9141                                 bblock = cfg->cbb;
9142                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9143                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9144                                         emit_widen = FALSE;
9145                                 }
9146                                 goto call_end;
9147                         }
9148
9149                         /* Inlining */
9150                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
9151                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9152                             mono_method_check_inlining (cfg, cmethod)) {
9153                                 int costs;
9154                                 gboolean always = FALSE;
9155
9156                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9157                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9158                                         /* Prevent inlining of methods that call wrappers */
9159                                         INLINE_FAILURE ("wrapper call");
9160                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
9161                                         always = TRUE;
9162                                 }
9163
9164                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
9165                                 if (costs) {
9166                                         cfg->real_offset += 5;
9167
9168                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9169                                                 /* *sp is already set by inline_method */
9170                                                 sp++;
9171                                                 push_res = FALSE;
9172                                         }
9173
9174                                         inline_costs += costs;
9175
9176                                         goto call_end;
9177                                 }
9178                         }
9179
9180                         /* Tail recursion elimination */
9181                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9182                                 gboolean has_vtargs = FALSE;
9183                                 int i;
9184
9185                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9186                                 INLINE_FAILURE ("tail call");
9187
9188                                 /* keep it simple */
9189                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9190                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9191                                                 has_vtargs = TRUE;
9192                                 }
9193
9194                                 if (!has_vtargs) {
9195                                         for (i = 0; i < n; ++i)
9196                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9197                                         MONO_INST_NEW (cfg, ins, OP_BR);
9198                                         MONO_ADD_INS (bblock, ins);
9199                                         tblock = start_bblock->out_bb [0];
9200                                         link_bblock (cfg, bblock, tblock);
9201                                         ins->inst_target_bb = tblock;
9202                                         start_new_bblock = 1;
9203
9204                                         /* skip the CEE_RET, too */
9205                                         if (ip_in_bb (cfg, bblock, ip + 5))
9206                                                 skip_ret = TRUE;
9207                                         push_res = FALSE;
9208                                         goto call_end;
9209                                 }
9210                         }
9211
9212                         inline_costs += 10 * num_calls++;
9213
9214                         /*
9215                          * Making generic calls out of gsharedvt methods.
9216                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9217                          * patching gshared method addresses into a gsharedvt method.
9218                          */
9219                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9220                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9221                                 MonoRgctxInfoType info_type;
9222
9223                                 if (virtual) {
9224                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9225                                                 //GSHAREDVT_FAILURE (*ip);
9226                                         // disable for possible remoting calls
9227                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9228                                                 GSHAREDVT_FAILURE (*ip);
9229                                         if (fsig->generic_param_count) {
9230                                                 /* virtual generic call */
9231                                                 g_assert (mono_use_imt);
9232                                                 g_assert (!imt_arg);
9233                                                 /* Same as the virtual generic case above */
9234                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9235                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9236                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9237                                                 vtable_arg = NULL;
9238                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9239                                                 /* This can happen when we call a fully instantiated iface method */
9240                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9241                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9242                                                 vtable_arg = NULL;
9243                                         }
9244                                 }
9245
9246                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9247                                         keep_this_alive = sp [0];
9248
9249                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9250                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9251                                 else
9252                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9253                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9254
9255                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9256                                 goto call_end;
9257                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9258                                 /*
9259                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
9260                                  */
9261                                 MonoInst *callee = addr;
9262
9263                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
9264                                         /* Not tested */
9265                                         GSHAREDVT_FAILURE (*ip);
9266
9267                                 addr = emit_get_rgctx_sig (cfg, context_used,
9268                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
9269                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
9270                                 goto call_end;
9271                         }
9272
9273                         /* Generic sharing */
9274
9275                         /*
9276                          * Use this if the callee is gsharedvt sharable too, since
9277                          * at runtime we might find an instantiation so the call cannot
9278                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9279                          */
9280                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9281                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9282                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9283                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9284                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9285                                 INLINE_FAILURE ("gshared");
9286
9287                                 g_assert (cfg->generic_sharing_context && cmethod);
9288                                 g_assert (!addr);
9289
9290                                 /*
9291                                  * We are compiling a call to a
9292                                  * generic method from shared code,
9293                                  * which means that we have to look up
9294                                  * the method in the rgctx and do an
9295                                  * indirect call.
9296                                  */
9297                                 if (fsig->hasthis)
9298                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9299
9300                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9301                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9302                                 goto call_end;
9303                         }
9304
9305                         /* Indirect calls */
9306                         if (addr) {
9307                                 if (call_opcode == CEE_CALL)
9308                                         g_assert (context_used);
9309                                 else if (call_opcode == CEE_CALLI)
9310                                         g_assert (!vtable_arg);
9311                                 else
9312                                         /* FIXME: what the hell is this??? */
9313                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
9314                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
9315
9316                                 /* Prevent inlining of methods with indirect calls */
9317                                 INLINE_FAILURE ("indirect call");
9318
9319                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9320                                         int info_type;
9321                                         gpointer info_data;
9322
9323                                         /* 
9324                                          * Instead of emitting an indirect call, emit a direct call
9325                                          * with the contents of the aotconst as the patch info.
9326                                          */
9327                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9328                                                 info_type = addr->inst_c1;
9329                                                 info_data = addr->inst_p0;
9330                                         } else {
9331                                                 info_type = addr->inst_right->inst_c1;
9332                                                 info_data = addr->inst_right->inst_left;
9333                                         }
9334                                         
9335                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9336                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9337                                                 NULLIFY_INS (addr);
9338                                                 goto call_end;
9339                                         }
9340                                 }
9341                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9342                                 goto call_end;
9343                         }
9344                                         
9345                         /* Array methods */
9346                         if (array_rank) {
9347                                 MonoInst *addr;
9348
9349                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9350                                         MonoInst *val = sp [fsig->param_count];
9351
9352                                         if (val->type == STACK_OBJ) {
9353                                                 MonoInst *iargs [2];
9354
9355                                                 iargs [0] = sp [0];
9356                                                 iargs [1] = val;
9357                                                 
9358                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9359                                         }
9360                                         
9361                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9362                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9363                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9364                                                 emit_write_barrier (cfg, addr, val);
9365                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cfg, cmethod->klass))
9366                                                 GSHAREDVT_FAILURE (*ip);
9367                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9368                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9369
9370                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9371                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9372                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9373                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9374                                         CHECK_TYPELOAD (cmethod->klass);
9375                                         
9376                                         readonly = FALSE;
9377                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9378                                         ins = addr;
9379                                 } else {
9380                                         g_assert_not_reached ();
9381                                 }
9382
9383                                 emit_widen = FALSE;
9384                                 goto call_end;
9385                         }
9386
9387                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9388                         if (ins)
9389                                 goto call_end;
9390
9391                         /* Tail prefix / tail call optimization */
9392
9393                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9394                         /* FIXME: runtime generic context pointer for jumps? */
9395                         /* FIXME: handle this for generic sharing eventually */
9396                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
9397                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9398                                 supported_tail_call = TRUE;
9399
9400                         if (supported_tail_call) {
9401                                 MonoCallInst *call;
9402
9403                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9404                                 INLINE_FAILURE ("tail call");
9405
9406                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9407
9408                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9409                                         /* Handle tail calls similarly to normal calls */
9410                                         tail_call = TRUE;
9411                                 } else {
9412                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9413
9414                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9415                                         call->tail_call = TRUE;
9416                                         call->method = cmethod;
9417                                         call->signature = mono_method_signature (cmethod);
9418
9419                                         /*
9420                                          * We implement tail calls by storing the actual arguments into the 
9421                                          * argument variables, then emitting a CEE_JMP.
9422                                          */
9423                                         for (i = 0; i < n; ++i) {
9424                                                 /* Prevent argument from being register allocated */
9425                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9426                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9427                                         }
9428                                         ins = (MonoInst*)call;
9429                                         ins->inst_p0 = cmethod;
9430                                         ins->inst_p1 = arg_array [0];
9431                                         MONO_ADD_INS (bblock, ins);
9432                                         link_bblock (cfg, bblock, end_bblock);                  
9433                                         start_new_bblock = 1;
9434
9435                                         // FIXME: Eliminate unreachable epilogs
9436
9437                                         /*
9438                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9439                                          * only reachable from this call.
9440                                          */
9441                                         GET_BBLOCK (cfg, tblock, ip + 5);
9442                                         if (tblock == bblock || tblock->in_count == 0)
9443                                                 skip_ret = TRUE;
9444                                         push_res = FALSE;
9445
9446                                         goto call_end;
9447                                 }
9448                         }
9449
9450                         /* 
9451                          * Synchronized wrappers.
9452                          * Its hard to determine where to replace a method with its synchronized
9453                          * wrapper without causing an infinite recursion. The current solution is
9454                          * to add the synchronized wrapper in the trampolines, and to
9455                          * change the called method to a dummy wrapper, and resolve that wrapper
9456                          * to the real method in mono_jit_compile_method ().
9457                          */
9458                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9459                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9460                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9461                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9462                         }
9463
9464                         /* Common call */
9465                         INLINE_FAILURE ("call");
9466                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9467                                                                                           imt_arg, vtable_arg);
9468
9469                         if (tail_call) {
9470                                 link_bblock (cfg, bblock, end_bblock);                  
9471                                 start_new_bblock = 1;
9472
9473                                 // FIXME: Eliminate unreachable epilogs
9474
9475                                 /*
9476                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9477                                  * only reachable from this call.
9478                                  */
9479                                 GET_BBLOCK (cfg, tblock, ip + 5);
9480                                 if (tblock == bblock || tblock->in_count == 0)
9481                                         skip_ret = TRUE;
9482                                 push_res = FALSE;
9483                         }
9484
9485                         call_end:
9486
9487                         /* End of call, INS should contain the result of the call, if any */
9488
9489                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9490                                 g_assert (ins);
9491                                 if (emit_widen)
9492                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9493                                 else
9494                                         *sp++ = ins;
9495                         }
9496
9497                         if (keep_this_alive) {
9498                                 MonoInst *dummy_use;
9499
9500                                 /* See mono_emit_method_call_full () */
9501                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9502                         }
9503
9504                         CHECK_CFG_EXCEPTION;
9505
9506                         ip += 5;
9507                         if (skip_ret) {
9508                                 g_assert (*ip == CEE_RET);
9509                                 ip += 1;
9510                         }
9511                         ins_flag = 0;
9512                         constrained_class = NULL;
9513                         if (need_seq_point)
9514                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9515                         break;
9516                 }
9517                 case CEE_RET:
9518                         if (cfg->method != method) {
9519                                 /* return from inlined method */
9520                                 /* 
9521                                  * If in_count == 0, that means the ret is unreachable due to
9522                                  * being preceeded by a throw. In that case, inline_method () will
9523                                  * handle setting the return value 
9524                                  * (test case: test_0_inline_throw ()).
9525                                  */
9526                                 if (return_var && cfg->cbb->in_count) {
9527                                         MonoType *ret_type = mono_method_signature (method)->ret;
9528
9529                                         MonoInst *store;
9530                                         CHECK_STACK (1);
9531                                         --sp;
9532
9533                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9534                                                 UNVERIFIED;
9535
9536                                         //g_assert (returnvar != -1);
9537                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9538                                         cfg->ret_var_set = TRUE;
9539                                 } 
9540                         } else {
9541                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9542
9543                                 if (cfg->lmf_var && cfg->cbb->in_count)
9544                                         emit_pop_lmf (cfg);
9545
9546                                 if (cfg->ret) {
9547                                         MonoType *ret_type = mini_get_underlying_type (cfg, mono_method_signature (method)->ret);
9548
9549                                         if (seq_points && !sym_seq_points) {
9550                                                 /* 
9551                                                  * Place a seq point here too even through the IL stack is not
9552                                                  * empty, so a step over on
9553                                                  * call <FOO>
9554                                                  * ret
9555                                                  * will work correctly.
9556                                                  */
9557                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9558                                                 MONO_ADD_INS (cfg->cbb, ins);
9559                                         }
9560
9561                                         g_assert (!return_var);
9562                                         CHECK_STACK (1);
9563                                         --sp;
9564
9565                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9566                                                 UNVERIFIED;
9567
9568                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9569                                                 MonoInst *ret_addr;
9570
9571                                                 if (!cfg->vret_addr) {
9572                                                         MonoInst *ins;
9573
9574                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9575                                                 } else {
9576                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9577
9578                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9579                                                         ins->klass = mono_class_from_mono_type (ret_type);
9580                                                 }
9581                                         } else {
9582 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9583                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9584                                                         MonoInst *iargs [1];
9585                                                         MonoInst *conv;
9586
9587                                                         iargs [0] = *sp;
9588                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9589                                                         mono_arch_emit_setret (cfg, method, conv);
9590                                                 } else {
9591                                                         mono_arch_emit_setret (cfg, method, *sp);
9592                                                 }
9593 #else
9594                                                 mono_arch_emit_setret (cfg, method, *sp);
9595 #endif
9596                                         }
9597                                 }
9598                         }
9599                         if (sp != stack_start)
9600                                 UNVERIFIED;
9601                         MONO_INST_NEW (cfg, ins, OP_BR);
9602                         ip++;
9603                         ins->inst_target_bb = end_bblock;
9604                         MONO_ADD_INS (bblock, ins);
9605                         link_bblock (cfg, bblock, end_bblock);
9606                         start_new_bblock = 1;
9607                         break;
9608                 case CEE_BR_S:
9609                         CHECK_OPSIZE (2);
9610                         MONO_INST_NEW (cfg, ins, OP_BR);
9611                         ip++;
9612                         target = ip + 1 + (signed char)(*ip);
9613                         ++ip;
9614                         GET_BBLOCK (cfg, tblock, target);
9615                         link_bblock (cfg, bblock, tblock);
9616                         ins->inst_target_bb = tblock;
9617                         if (sp != stack_start) {
9618                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9619                                 sp = stack_start;
9620                                 CHECK_UNVERIFIABLE (cfg);
9621                         }
9622                         MONO_ADD_INS (bblock, ins);
9623                         start_new_bblock = 1;
9624                         inline_costs += BRANCH_COST;
9625                         break;
9626                 case CEE_BEQ_S:
9627                 case CEE_BGE_S:
9628                 case CEE_BGT_S:
9629                 case CEE_BLE_S:
9630                 case CEE_BLT_S:
9631                 case CEE_BNE_UN_S:
9632                 case CEE_BGE_UN_S:
9633                 case CEE_BGT_UN_S:
9634                 case CEE_BLE_UN_S:
9635                 case CEE_BLT_UN_S:
9636                         CHECK_OPSIZE (2);
9637                         CHECK_STACK (2);
9638                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9639                         ip++;
9640                         target = ip + 1 + *(signed char*)ip;
9641                         ip++;
9642
9643                         ADD_BINCOND (NULL);
9644
9645                         sp = stack_start;
9646                         inline_costs += BRANCH_COST;
9647                         break;
9648                 case CEE_BR:
9649                         CHECK_OPSIZE (5);
9650                         MONO_INST_NEW (cfg, ins, OP_BR);
9651                         ip++;
9652
9653                         target = ip + 4 + (gint32)read32(ip);
9654                         ip += 4;
9655                         GET_BBLOCK (cfg, tblock, target);
9656                         link_bblock (cfg, bblock, tblock);
9657                         ins->inst_target_bb = tblock;
9658                         if (sp != stack_start) {
9659                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9660                                 sp = stack_start;
9661                                 CHECK_UNVERIFIABLE (cfg);
9662                         }
9663
9664                         MONO_ADD_INS (bblock, ins);
9665
9666                         start_new_bblock = 1;
9667                         inline_costs += BRANCH_COST;
9668                         break;
9669                 case CEE_BRFALSE_S:
9670                 case CEE_BRTRUE_S:
9671                 case CEE_BRFALSE:
9672                 case CEE_BRTRUE: {
9673                         MonoInst *cmp;
9674                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9675                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9676                         guint32 opsize = is_short ? 1 : 4;
9677
9678                         CHECK_OPSIZE (opsize);
9679                         CHECK_STACK (1);
9680                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9681                                 UNVERIFIED;
9682                         ip ++;
9683                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9684                         ip += opsize;
9685
9686                         sp--;
9687
9688                         GET_BBLOCK (cfg, tblock, target);
9689                         link_bblock (cfg, bblock, tblock);
9690                         GET_BBLOCK (cfg, tblock, ip);
9691                         link_bblock (cfg, bblock, tblock);
9692
9693                         if (sp != stack_start) {
9694                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9695                                 CHECK_UNVERIFIABLE (cfg);
9696                         }
9697
9698                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9699                         cmp->sreg1 = sp [0]->dreg;
9700                         type_from_op (cfg, cmp, sp [0], NULL);
9701                         CHECK_TYPE (cmp);
9702
9703 #if SIZEOF_REGISTER == 4
9704                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9705                                 /* Convert it to OP_LCOMPARE */
9706                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9707                                 ins->type = STACK_I8;
9708                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9709                                 ins->inst_l = 0;
9710                                 MONO_ADD_INS (bblock, ins);
9711                                 cmp->opcode = OP_LCOMPARE;
9712                                 cmp->sreg2 = ins->dreg;
9713                         }
9714 #endif
9715                         MONO_ADD_INS (bblock, cmp);
9716
9717                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9718                         type_from_op (cfg, ins, sp [0], NULL);
9719                         MONO_ADD_INS (bblock, ins);
9720                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9721                         GET_BBLOCK (cfg, tblock, target);
9722                         ins->inst_true_bb = tblock;
9723                         GET_BBLOCK (cfg, tblock, ip);
9724                         ins->inst_false_bb = tblock;
9725                         start_new_bblock = 2;
9726
9727                         sp = stack_start;
9728                         inline_costs += BRANCH_COST;
9729                         break;
9730                 }
9731                 case CEE_BEQ:
9732                 case CEE_BGE:
9733                 case CEE_BGT:
9734                 case CEE_BLE:
9735                 case CEE_BLT:
9736                 case CEE_BNE_UN:
9737                 case CEE_BGE_UN:
9738                 case CEE_BGT_UN:
9739                 case CEE_BLE_UN:
9740                 case CEE_BLT_UN:
9741                         CHECK_OPSIZE (5);
9742                         CHECK_STACK (2);
9743                         MONO_INST_NEW (cfg, ins, *ip);
9744                         ip++;
9745                         target = ip + 4 + (gint32)read32(ip);
9746                         ip += 4;
9747
9748                         ADD_BINCOND (NULL);
9749
9750                         sp = stack_start;
9751                         inline_costs += BRANCH_COST;
9752                         break;
9753                 case CEE_SWITCH: {
9754                         MonoInst *src1;
9755                         MonoBasicBlock **targets;
9756                         MonoBasicBlock *default_bblock;
9757                         MonoJumpInfoBBTable *table;
9758                         int offset_reg = alloc_preg (cfg);
9759                         int target_reg = alloc_preg (cfg);
9760                         int table_reg = alloc_preg (cfg);
9761                         int sum_reg = alloc_preg (cfg);
9762                         gboolean use_op_switch;
9763
9764                         CHECK_OPSIZE (5);
9765                         CHECK_STACK (1);
9766                         n = read32 (ip + 1);
9767                         --sp;
9768                         src1 = sp [0];
9769                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9770                                 UNVERIFIED;
9771
9772                         ip += 5;
9773                         CHECK_OPSIZE (n * sizeof (guint32));
9774                         target = ip + n * sizeof (guint32);
9775
9776                         GET_BBLOCK (cfg, default_bblock, target);
9777                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9778
9779                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9780                         for (i = 0; i < n; ++i) {
9781                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9782                                 targets [i] = tblock;
9783                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9784                                 ip += 4;
9785                         }
9786
9787                         if (sp != stack_start) {
9788                                 /* 
9789                                  * Link the current bb with the targets as well, so handle_stack_args
9790                                  * will set their in_stack correctly.
9791                                  */
9792                                 link_bblock (cfg, bblock, default_bblock);
9793                                 for (i = 0; i < n; ++i)
9794                                         link_bblock (cfg, bblock, targets [i]);
9795
9796                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9797                                 sp = stack_start;
9798                                 CHECK_UNVERIFIABLE (cfg);
9799                         }
9800
9801                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9802                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9803                         bblock = cfg->cbb;
9804
9805                         for (i = 0; i < n; ++i)
9806                                 link_bblock (cfg, bblock, targets [i]);
9807
9808                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9809                         table->table = targets;
9810                         table->table_size = n;
9811
9812                         use_op_switch = FALSE;
9813 #ifdef TARGET_ARM
9814                         /* ARM implements SWITCH statements differently */
9815                         /* FIXME: Make it use the generic implementation */
9816                         if (!cfg->compile_aot)
9817                                 use_op_switch = TRUE;
9818 #endif
9819
9820                         if (COMPILE_LLVM (cfg))
9821                                 use_op_switch = TRUE;
9822
9823                         cfg->cbb->has_jump_table = 1;
9824
9825                         if (use_op_switch) {
9826                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9827                                 ins->sreg1 = src1->dreg;
9828                                 ins->inst_p0 = table;
9829                                 ins->inst_many_bb = targets;
9830                                 ins->klass = GUINT_TO_POINTER (n);
9831                                 MONO_ADD_INS (cfg->cbb, ins);
9832                         } else {
9833                                 if (sizeof (gpointer) == 8)
9834                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9835                                 else
9836                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9837
9838 #if SIZEOF_REGISTER == 8
9839                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9840                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9841 #endif
9842
9843                                 if (cfg->compile_aot) {
9844                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9845                                 } else {
9846                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9847                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9848                                         ins->inst_p0 = table;
9849                                         ins->dreg = table_reg;
9850                                         MONO_ADD_INS (cfg->cbb, ins);
9851                                 }
9852
9853                                 /* FIXME: Use load_memindex */
9854                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9855                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9856                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9857                         }
9858                         start_new_bblock = 1;
9859                         inline_costs += (BRANCH_COST * 2);
9860                         break;
9861                 }
9862                 case CEE_LDIND_I1:
9863                 case CEE_LDIND_U1:
9864                 case CEE_LDIND_I2:
9865                 case CEE_LDIND_U2:
9866                 case CEE_LDIND_I4:
9867                 case CEE_LDIND_U4:
9868                 case CEE_LDIND_I8:
9869                 case CEE_LDIND_I:
9870                 case CEE_LDIND_R4:
9871                 case CEE_LDIND_R8:
9872                 case CEE_LDIND_REF:
9873                         CHECK_STACK (1);
9874                         --sp;
9875
9876                         switch (*ip) {
9877                         case CEE_LDIND_R4:
9878                         case CEE_LDIND_R8:
9879                                 dreg = alloc_freg (cfg);
9880                                 break;
9881                         case CEE_LDIND_I8:
9882                                 dreg = alloc_lreg (cfg);
9883                                 break;
9884                         case CEE_LDIND_REF:
9885                                 dreg = alloc_ireg_ref (cfg);
9886                                 break;
9887                         default:
9888                                 dreg = alloc_preg (cfg);
9889                         }
9890
9891                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9892                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9893                         if (*ip == CEE_LDIND_R4)
9894                                 ins->type = cfg->r4_stack_type;
9895                         ins->flags |= ins_flag;
9896                         MONO_ADD_INS (bblock, ins);
9897                         *sp++ = ins;
9898                         if (ins_flag & MONO_INST_VOLATILE) {
9899                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9900                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9901                         }
9902                         ins_flag = 0;
9903                         ++ip;
9904                         break;
9905                 case CEE_STIND_REF:
9906                 case CEE_STIND_I1:
9907                 case CEE_STIND_I2:
9908                 case CEE_STIND_I4:
9909                 case CEE_STIND_I8:
9910                 case CEE_STIND_R4:
9911                 case CEE_STIND_R8:
9912                 case CEE_STIND_I:
9913                         CHECK_STACK (2);
9914                         sp -= 2;
9915
9916                         if (ins_flag & MONO_INST_VOLATILE) {
9917                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9918                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9919                         }
9920
9921                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9922                         ins->flags |= ins_flag;
9923                         ins_flag = 0;
9924
9925                         MONO_ADD_INS (bblock, ins);
9926
9927                         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)))
9928                                 emit_write_barrier (cfg, sp [0], sp [1]);
9929
9930                         inline_costs += 1;
9931                         ++ip;
9932                         break;
9933
9934                 case CEE_MUL:
9935                         CHECK_STACK (2);
9936
9937                         MONO_INST_NEW (cfg, ins, (*ip));
9938                         sp -= 2;
9939                         ins->sreg1 = sp [0]->dreg;
9940                         ins->sreg2 = sp [1]->dreg;
9941                         type_from_op (cfg, ins, sp [0], sp [1]);
9942                         CHECK_TYPE (ins);
9943                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9944
9945                         /* Use the immediate opcodes if possible */
9946                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9947                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9948                                 if (imm_opcode != -1) {
9949                                         ins->opcode = imm_opcode;
9950                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9951                                         ins->sreg2 = -1;
9952
9953                                         NULLIFY_INS (sp [1]);
9954                                 }
9955                         }
9956
9957                         MONO_ADD_INS ((cfg)->cbb, (ins));
9958
9959                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
9960                         ip++;
9961                         break;
9962                 case CEE_ADD:
9963                 case CEE_SUB:
9964                 case CEE_DIV:
9965                 case CEE_DIV_UN:
9966                 case CEE_REM:
9967                 case CEE_REM_UN:
9968                 case CEE_AND:
9969                 case CEE_OR:
9970                 case CEE_XOR:
9971                 case CEE_SHL:
9972                 case CEE_SHR:
9973                 case CEE_SHR_UN:
9974                         CHECK_STACK (2);
9975
9976                         MONO_INST_NEW (cfg, ins, (*ip));
9977                         sp -= 2;
9978                         ins->sreg1 = sp [0]->dreg;
9979                         ins->sreg2 = sp [1]->dreg;
9980                         type_from_op (cfg, ins, sp [0], sp [1]);
9981                         CHECK_TYPE (ins);
9982                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
9983                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9984
9985                         /* FIXME: Pass opcode to is_inst_imm */
9986
9987                         /* Use the immediate opcodes if possible */
9988                         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)) {
9989                                 int imm_opcode;
9990
9991                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9992 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9993                                 /* Keep emulated opcodes which are optimized away later */
9994                                 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) {
9995                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9996                                 }
9997 #endif
9998                                 if (imm_opcode != -1) {
9999                                         ins->opcode = imm_opcode;
10000                                         if (sp [1]->opcode == OP_I8CONST) {
10001 #if SIZEOF_REGISTER == 8
10002                                                 ins->inst_imm = sp [1]->inst_l;
10003 #else
10004                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10005                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10006 #endif
10007                                         }
10008                                         else
10009                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10010                                         ins->sreg2 = -1;
10011
10012                                         /* Might be followed by an instruction added by add_widen_op */
10013                                         if (sp [1]->next == NULL)
10014                                                 NULLIFY_INS (sp [1]);
10015                                 }
10016                         }
10017                         MONO_ADD_INS ((cfg)->cbb, (ins));
10018
10019                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
10020                         ip++;
10021                         break;
10022                 case CEE_NEG:
10023                 case CEE_NOT:
10024                 case CEE_CONV_I1:
10025                 case CEE_CONV_I2:
10026                 case CEE_CONV_I4:
10027                 case CEE_CONV_R4:
10028                 case CEE_CONV_R8:
10029                 case CEE_CONV_U4:
10030                 case CEE_CONV_I8:
10031                 case CEE_CONV_U8:
10032                 case CEE_CONV_OVF_I8:
10033                 case CEE_CONV_OVF_U8:
10034                 case CEE_CONV_R_UN:
10035                         CHECK_STACK (1);
10036
10037                         /* Special case this earlier so we have long constants in the IR */
10038                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10039                                 int data = sp [-1]->inst_c0;
10040                                 sp [-1]->opcode = OP_I8CONST;
10041                                 sp [-1]->type = STACK_I8;
10042 #if SIZEOF_REGISTER == 8
10043                                 if ((*ip) == CEE_CONV_U8)
10044                                         sp [-1]->inst_c0 = (guint32)data;
10045                                 else
10046                                         sp [-1]->inst_c0 = data;
10047 #else
10048                                 sp [-1]->inst_ls_word = data;
10049                                 if ((*ip) == CEE_CONV_U8)
10050                                         sp [-1]->inst_ms_word = 0;
10051                                 else
10052                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10053 #endif
10054                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10055                         }
10056                         else {
10057                                 ADD_UNOP (*ip);
10058                         }
10059                         ip++;
10060                         break;
10061                 case CEE_CONV_OVF_I4:
10062                 case CEE_CONV_OVF_I1:
10063                 case CEE_CONV_OVF_I2:
10064                 case CEE_CONV_OVF_I:
10065                 case CEE_CONV_OVF_U:
10066                         CHECK_STACK (1);
10067
10068                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10069                                 ADD_UNOP (CEE_CONV_OVF_I8);
10070                                 ADD_UNOP (*ip);
10071                         } else {
10072                                 ADD_UNOP (*ip);
10073                         }
10074                         ip++;
10075                         break;
10076                 case CEE_CONV_OVF_U1:
10077                 case CEE_CONV_OVF_U2:
10078                 case CEE_CONV_OVF_U4:
10079                         CHECK_STACK (1);
10080
10081                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10082                                 ADD_UNOP (CEE_CONV_OVF_U8);
10083                                 ADD_UNOP (*ip);
10084                         } else {
10085                                 ADD_UNOP (*ip);
10086                         }
10087                         ip++;
10088                         break;
10089                 case CEE_CONV_OVF_I1_UN:
10090                 case CEE_CONV_OVF_I2_UN:
10091                 case CEE_CONV_OVF_I4_UN:
10092                 case CEE_CONV_OVF_I8_UN:
10093                 case CEE_CONV_OVF_U1_UN:
10094                 case CEE_CONV_OVF_U2_UN:
10095                 case CEE_CONV_OVF_U4_UN:
10096                 case CEE_CONV_OVF_U8_UN:
10097                 case CEE_CONV_OVF_I_UN:
10098                 case CEE_CONV_OVF_U_UN:
10099                 case CEE_CONV_U2:
10100                 case CEE_CONV_U1:
10101                 case CEE_CONV_I:
10102                 case CEE_CONV_U:
10103                         CHECK_STACK (1);
10104                         ADD_UNOP (*ip);
10105                         CHECK_CFG_EXCEPTION;
10106                         ip++;
10107                         break;
10108                 case CEE_ADD_OVF:
10109                 case CEE_ADD_OVF_UN:
10110                 case CEE_MUL_OVF:
10111                 case CEE_MUL_OVF_UN:
10112                 case CEE_SUB_OVF:
10113                 case CEE_SUB_OVF_UN:
10114                         CHECK_STACK (2);
10115                         ADD_BINOP (*ip);
10116                         ip++;
10117                         break;
10118                 case CEE_CPOBJ:
10119                         GSHAREDVT_FAILURE (*ip);
10120                         CHECK_OPSIZE (5);
10121                         CHECK_STACK (2);
10122                         token = read32 (ip + 1);
10123                         klass = mini_get_class (method, token, generic_context);
10124                         CHECK_TYPELOAD (klass);
10125                         sp -= 2;
10126                         if (generic_class_is_reference_type (cfg, klass)) {
10127                                 MonoInst *store, *load;
10128                                 int dreg = alloc_ireg_ref (cfg);
10129
10130                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10131                                 load->flags |= ins_flag;
10132                                 MONO_ADD_INS (cfg->cbb, load);
10133
10134                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10135                                 store->flags |= ins_flag;
10136                                 MONO_ADD_INS (cfg->cbb, store);
10137
10138                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10139                                         emit_write_barrier (cfg, sp [0], sp [1]);
10140                         } else {
10141                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10142                         }
10143                         ins_flag = 0;
10144                         ip += 5;
10145                         break;
10146                 case CEE_LDOBJ: {
10147                         int loc_index = -1;
10148                         int stloc_len = 0;
10149
10150                         CHECK_OPSIZE (5);
10151                         CHECK_STACK (1);
10152                         --sp;
10153                         token = read32 (ip + 1);
10154                         klass = mini_get_class (method, token, generic_context);
10155                         CHECK_TYPELOAD (klass);
10156
10157                         /* Optimize the common ldobj+stloc combination */
10158                         switch (ip [5]) {
10159                         case CEE_STLOC_S:
10160                                 loc_index = ip [6];
10161                                 stloc_len = 2;
10162                                 break;
10163                         case CEE_STLOC_0:
10164                         case CEE_STLOC_1:
10165                         case CEE_STLOC_2:
10166                         case CEE_STLOC_3:
10167                                 loc_index = ip [5] - CEE_STLOC_0;
10168                                 stloc_len = 1;
10169                                 break;
10170                         default:
10171                                 break;
10172                         }
10173
10174                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
10175                                 CHECK_LOCAL (loc_index);
10176
10177                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10178                                 ins->dreg = cfg->locals [loc_index]->dreg;
10179                                 ins->flags |= ins_flag;
10180                                 ip += 5;
10181                                 ip += stloc_len;
10182                                 if (ins_flag & MONO_INST_VOLATILE) {
10183                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10184                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10185                                 }
10186                                 ins_flag = 0;
10187                                 break;
10188                         }
10189
10190                         /* Optimize the ldobj+stobj combination */
10191                         /* The reference case ends up being a load+store anyway */
10192                         /* Skip this if the operation is volatile. */
10193                         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)) {
10194                                 CHECK_STACK (1);
10195
10196                                 sp --;
10197
10198                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10199
10200                                 ip += 5 + 5;
10201                                 ins_flag = 0;
10202                                 break;
10203                         }
10204
10205                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10206                         ins->flags |= ins_flag;
10207                         *sp++ = ins;
10208
10209                         if (ins_flag & MONO_INST_VOLATILE) {
10210                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10211                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10212                         }
10213
10214                         ip += 5;
10215                         ins_flag = 0;
10216                         inline_costs += 1;
10217                         break;
10218                 }
10219                 case CEE_LDSTR:
10220                         CHECK_STACK_OVF (1);
10221                         CHECK_OPSIZE (5);
10222                         n = read32 (ip + 1);
10223
10224                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10225                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10226                                 ins->type = STACK_OBJ;
10227                                 *sp = ins;
10228                         }
10229                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10230                                 MonoInst *iargs [1];
10231                                 char *str = mono_method_get_wrapper_data (method, n);
10232
10233                                 if (cfg->compile_aot)
10234                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10235                                 else
10236                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10237                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10238                         } else {
10239                                 if (cfg->opt & MONO_OPT_SHARED) {
10240                                         MonoInst *iargs [3];
10241
10242                                         if (cfg->compile_aot) {
10243                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10244                                         }
10245                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10246                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10247                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10248                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10249                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10250                                 } else {
10251                                         if (bblock->out_of_line) {
10252                                                 MonoInst *iargs [2];
10253
10254                                                 if (image == mono_defaults.corlib) {
10255                                                         /* 
10256                                                          * Avoid relocations in AOT and save some space by using a 
10257                                                          * version of helper_ldstr specialized to mscorlib.
10258                                                          */
10259                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10260                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10261                                                 } else {
10262                                                         /* Avoid creating the string object */
10263                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10264                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10265                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10266                                                 }
10267                                         } 
10268                                         else
10269                                         if (cfg->compile_aot) {
10270                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10271                                                 *sp = ins;
10272                                                 MONO_ADD_INS (bblock, ins);
10273                                         } 
10274                                         else {
10275                                                 NEW_PCONST (cfg, ins, NULL);
10276                                                 ins->type = STACK_OBJ;
10277                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10278                                                 if (!ins->inst_p0)
10279                                                         OUT_OF_MEMORY_FAILURE;
10280
10281                                                 *sp = ins;
10282                                                 MONO_ADD_INS (bblock, ins);
10283                                         }
10284                                 }
10285                         }
10286
10287                         sp++;
10288                         ip += 5;
10289                         break;
10290                 case CEE_NEWOBJ: {
10291                         MonoInst *iargs [2];
10292                         MonoMethodSignature *fsig;
10293                         MonoInst this_ins;
10294                         MonoInst *alloc;
10295                         MonoInst *vtable_arg = NULL;
10296
10297                         CHECK_OPSIZE (5);
10298                         token = read32 (ip + 1);
10299                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10300                         if (!cmethod || mono_loader_get_last_error ())
10301                                 LOAD_ERROR;
10302                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10303                         CHECK_CFG_ERROR;
10304
10305                         mono_save_token_info (cfg, image, token, cmethod);
10306
10307                         if (!mono_class_init (cmethod->klass))
10308                                 TYPE_LOAD_ERROR (cmethod->klass);
10309
10310                         context_used = mini_method_check_context_used (cfg, cmethod);
10311
10312                         if (mono_security_cas_enabled ()) {
10313                                 if (check_linkdemand (cfg, method, cmethod))
10314                                         INLINE_FAILURE ("linkdemand");
10315                                 CHECK_CFG_EXCEPTION;
10316                         } else if (mono_security_core_clr_enabled ()) {
10317                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10318                         }
10319
10320                         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)) {
10321                                 emit_generic_class_init (cfg, cmethod->klass);
10322                                 CHECK_TYPELOAD (cmethod->klass);
10323                         }
10324
10325                         /*
10326                         if (cfg->gsharedvt) {
10327                                 if (mini_is_gsharedvt_variable_signature (sig))
10328                                         GSHAREDVT_FAILURE (*ip);
10329                         }
10330                         */
10331
10332                         n = fsig->param_count;
10333                         CHECK_STACK (n);
10334
10335                         /* 
10336                          * Generate smaller code for the common newobj <exception> instruction in
10337                          * argument checking code.
10338                          */
10339                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10340                                 is_exception_class (cmethod->klass) && n <= 2 &&
10341                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10342                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10343                                 MonoInst *iargs [3];
10344
10345                                 sp -= n;
10346
10347                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10348                                 switch (n) {
10349                                 case 0:
10350                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10351                                         break;
10352                                 case 1:
10353                                         iargs [1] = sp [0];
10354                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10355                                         break;
10356                                 case 2:
10357                                         iargs [1] = sp [0];
10358                                         iargs [2] = sp [1];
10359                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10360                                         break;
10361                                 default:
10362                                         g_assert_not_reached ();
10363                                 }
10364
10365                                 ip += 5;
10366                                 inline_costs += 5;
10367                                 break;
10368                         }
10369
10370                         /* move the args to allow room for 'this' in the first position */
10371                         while (n--) {
10372                                 --sp;
10373                                 sp [1] = sp [0];
10374                         }
10375
10376                         /* check_call_signature () requires sp[0] to be set */
10377                         this_ins.type = STACK_OBJ;
10378                         sp [0] = &this_ins;
10379                         if (check_call_signature (cfg, fsig, sp))
10380                                 UNVERIFIED;
10381
10382                         iargs [0] = NULL;
10383
10384                         if (mini_class_is_system_array (cmethod->klass)) {
10385                                 *sp = emit_get_rgctx_method (cfg, context_used,
10386                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10387
10388                                 /* Avoid varargs in the common case */
10389                                 if (fsig->param_count == 1)
10390                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10391                                 else if (fsig->param_count == 2)
10392                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10393                                 else if (fsig->param_count == 3)
10394                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10395                                 else if (fsig->param_count == 4)
10396                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10397                                 else
10398                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10399                         } else if (cmethod->string_ctor) {
10400                                 g_assert (!context_used);
10401                                 g_assert (!vtable_arg);
10402                                 /* we simply pass a null pointer */
10403                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10404                                 /* now call the string ctor */
10405                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10406                         } else {
10407                                 if (cmethod->klass->valuetype) {
10408                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10409                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10410                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10411
10412                                         alloc = NULL;
10413
10414                                         /* 
10415                                          * The code generated by mini_emit_virtual_call () expects
10416                                          * iargs [0] to be a boxed instance, but luckily the vcall
10417                                          * will be transformed into a normal call there.
10418                                          */
10419                                 } else if (context_used) {
10420                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10421                                         *sp = alloc;
10422                                 } else {
10423                                         MonoVTable *vtable = NULL;
10424
10425                                         if (!cfg->compile_aot)
10426                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10427                                         CHECK_TYPELOAD (cmethod->klass);
10428
10429                                         /*
10430                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10431                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10432                                          * As a workaround, we call class cctors before allocating objects.
10433                                          */
10434                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10435                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10436                                                 if (cfg->verbose_level > 2)
10437                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10438                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10439                                         }
10440
10441                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10442                                         *sp = alloc;
10443                                 }
10444                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10445
10446                                 if (alloc)
10447                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10448
10449                                 /* Now call the actual ctor */
10450                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10451                                 CHECK_CFG_EXCEPTION;
10452                         }
10453
10454                         if (alloc == NULL) {
10455                                 /* Valuetype */
10456                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10457                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10458                                 *sp++= ins;
10459                         } else {
10460                                 *sp++ = alloc;
10461                         }
10462                         
10463                         ip += 5;
10464                         inline_costs += 5;
10465                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10466                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10467                         break;
10468                 }
10469                 case CEE_CASTCLASS:
10470                         CHECK_STACK (1);
10471                         --sp;
10472                         CHECK_OPSIZE (5);
10473                         token = read32 (ip + 1);
10474                         klass = mini_get_class (method, token, generic_context);
10475                         CHECK_TYPELOAD (klass);
10476                         if (sp [0]->type != STACK_OBJ)
10477                                 UNVERIFIED;
10478
10479                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10480                         CHECK_CFG_EXCEPTION;
10481
10482                         *sp ++ = ins;
10483                         ip += 5;
10484                         break;
10485                 case CEE_ISINST: {
10486                         CHECK_STACK (1);
10487                         --sp;
10488                         CHECK_OPSIZE (5);
10489                         token = read32 (ip + 1);
10490                         klass = mini_get_class (method, token, generic_context);
10491                         CHECK_TYPELOAD (klass);
10492                         if (sp [0]->type != STACK_OBJ)
10493                                 UNVERIFIED;
10494  
10495                         context_used = mini_class_check_context_used (cfg, klass);
10496
10497                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10498                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10499                                 MonoInst *args [3];
10500
10501                                 /* obj */
10502                                 args [0] = *sp;
10503
10504                                 /* klass */
10505                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10506
10507                                 /* inline cache*/
10508                                 if (cfg->compile_aot)
10509                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
10510                                 else
10511                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10512
10513                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10514                                 ip += 5;
10515                                 inline_costs += 2;
10516                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10517                                 MonoMethod *mono_isinst;
10518                                 MonoInst *iargs [1];
10519                                 int costs;
10520
10521                                 mono_isinst = mono_marshal_get_isinst (klass); 
10522                                 iargs [0] = sp [0];
10523
10524                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10525                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10526                                 CHECK_CFG_EXCEPTION;
10527                                 g_assert (costs > 0);
10528                                 
10529                                 ip += 5;
10530                                 cfg->real_offset += 5;
10531
10532                                 *sp++= iargs [0];
10533
10534                                 inline_costs += costs;
10535                         }
10536                         else {
10537                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10538                                 CHECK_CFG_EXCEPTION;
10539                                 bblock = cfg->cbb;
10540                                 *sp ++ = ins;
10541                                 ip += 5;
10542                         }
10543                         break;
10544                 }
10545                 case CEE_UNBOX_ANY: {
10546                         MonoInst *res, *addr;
10547
10548                         CHECK_STACK (1);
10549                         --sp;
10550                         CHECK_OPSIZE (5);
10551                         token = read32 (ip + 1);
10552                         klass = mini_get_class (method, token, generic_context);
10553                         CHECK_TYPELOAD (klass);
10554
10555                         mono_save_token_info (cfg, image, token, klass);
10556
10557                         context_used = mini_class_check_context_used (cfg, klass);
10558
10559                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10560                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10561                                 inline_costs += 2;
10562                         } else if (generic_class_is_reference_type (cfg, klass)) {
10563                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10564                                 CHECK_CFG_EXCEPTION;
10565                         } else if (mono_class_is_nullable (klass)) {
10566                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10567                         } else {
10568                                 addr = handle_unbox (cfg, klass, sp, context_used);
10569                                 /* LDOBJ */
10570                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10571                                 res = ins;
10572                                 inline_costs += 2;
10573                         }
10574
10575                         *sp ++ = res;
10576                         ip += 5;
10577                         break;
10578                 }
10579                 case CEE_BOX: {
10580                         MonoInst *val;
10581                         MonoClass *enum_class;
10582                         MonoMethod *has_flag;
10583
10584                         CHECK_STACK (1);
10585                         --sp;
10586                         val = *sp;
10587                         CHECK_OPSIZE (5);
10588                         token = read32 (ip + 1);
10589                         klass = mini_get_class (method, token, generic_context);
10590                         CHECK_TYPELOAD (klass);
10591
10592                         mono_save_token_info (cfg, image, token, klass);
10593
10594                         context_used = mini_class_check_context_used (cfg, klass);
10595
10596                         if (generic_class_is_reference_type (cfg, klass)) {
10597                                 *sp++ = val;
10598                                 ip += 5;
10599                                 break;
10600                         }
10601
10602                         if (klass == mono_defaults.void_class)
10603                                 UNVERIFIED;
10604                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10605                                 UNVERIFIED;
10606                         /* frequent check in generic code: box (struct), brtrue */
10607
10608                         /*
10609                          * Look for:
10610                          *
10611                          *   <push int/long ptr>
10612                          *   <push int/long>
10613                          *   box MyFlags
10614                          *   constrained. MyFlags
10615                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10616                          *
10617                          * If we find this sequence and the operand types on box and constrained
10618                          * are equal, we can emit a specialized instruction sequence instead of
10619                          * the very slow HasFlag () call.
10620                          */
10621                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10622                             /* Cheap checks first. */
10623                             ip + 5 + 6 + 5 < end &&
10624                             ip [5] == CEE_PREFIX1 &&
10625                             ip [6] == CEE_CONSTRAINED_ &&
10626                             ip [11] == CEE_CALLVIRT &&
10627                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10628                             mono_class_is_enum (klass) &&
10629                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10630                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10631                             has_flag->klass == mono_defaults.enum_class &&
10632                             !strcmp (has_flag->name, "HasFlag") &&
10633                             has_flag->signature->hasthis &&
10634                             has_flag->signature->param_count == 1) {
10635                                 CHECK_TYPELOAD (enum_class);
10636
10637                                 if (enum_class == klass) {
10638                                         MonoInst *enum_this, *enum_flag;
10639
10640                                         ip += 5 + 6 + 5;
10641                                         --sp;
10642
10643                                         enum_this = sp [0];
10644                                         enum_flag = sp [1];
10645
10646                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10647                                         break;
10648                                 }
10649                         }
10650
10651                         // FIXME: LLVM can't handle the inconsistent bb linking
10652                         if (!mono_class_is_nullable (klass) &&
10653                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10654                                 (ip [5] == CEE_BRTRUE || 
10655                                  ip [5] == CEE_BRTRUE_S ||
10656                                  ip [5] == CEE_BRFALSE ||
10657                                  ip [5] == CEE_BRFALSE_S)) {
10658                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10659                                 int dreg;
10660                                 MonoBasicBlock *true_bb, *false_bb;
10661
10662                                 ip += 5;
10663
10664                                 if (cfg->verbose_level > 3) {
10665                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10666                                         printf ("<box+brtrue opt>\n");
10667                                 }
10668
10669                                 switch (*ip) {
10670                                 case CEE_BRTRUE_S:
10671                                 case CEE_BRFALSE_S:
10672                                         CHECK_OPSIZE (2);
10673                                         ip++;
10674                                         target = ip + 1 + (signed char)(*ip);
10675                                         ip++;
10676                                         break;
10677                                 case CEE_BRTRUE:
10678                                 case CEE_BRFALSE:
10679                                         CHECK_OPSIZE (5);
10680                                         ip++;
10681                                         target = ip + 4 + (gint)(read32 (ip));
10682                                         ip += 4;
10683                                         break;
10684                                 default:
10685                                         g_assert_not_reached ();
10686                                 }
10687
10688                                 /* 
10689                                  * We need to link both bblocks, since it is needed for handling stack
10690                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10691                                  * Branching to only one of them would lead to inconsistencies, so
10692                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10693                                  */
10694                                 GET_BBLOCK (cfg, true_bb, target);
10695                                 GET_BBLOCK (cfg, false_bb, ip);
10696
10697                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10698                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10699
10700                                 if (sp != stack_start) {
10701                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10702                                         sp = stack_start;
10703                                         CHECK_UNVERIFIABLE (cfg);
10704                                 }
10705
10706                                 if (COMPILE_LLVM (cfg)) {
10707                                         dreg = alloc_ireg (cfg);
10708                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10709                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10710
10711                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10712                                 } else {
10713                                         /* The JIT can't eliminate the iconst+compare */
10714                                         MONO_INST_NEW (cfg, ins, OP_BR);
10715                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10716                                         MONO_ADD_INS (cfg->cbb, ins);
10717                                 }
10718
10719                                 start_new_bblock = 1;
10720                                 break;
10721                         }
10722
10723                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10724
10725                         CHECK_CFG_EXCEPTION;
10726                         ip += 5;
10727                         inline_costs += 1;
10728                         break;
10729                 }
10730                 case CEE_UNBOX: {
10731                         CHECK_STACK (1);
10732                         --sp;
10733                         CHECK_OPSIZE (5);
10734                         token = read32 (ip + 1);
10735                         klass = mini_get_class (method, token, generic_context);
10736                         CHECK_TYPELOAD (klass);
10737
10738                         mono_save_token_info (cfg, image, token, klass);
10739
10740                         context_used = mini_class_check_context_used (cfg, klass);
10741
10742                         if (mono_class_is_nullable (klass)) {
10743                                 MonoInst *val;
10744
10745                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10746                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10747
10748                                 *sp++= ins;
10749                         } else {
10750                                 ins = handle_unbox (cfg, klass, sp, context_used);
10751                                 *sp++ = ins;
10752                         }
10753                         ip += 5;
10754                         inline_costs += 2;
10755                         break;
10756                 }
10757                 case CEE_LDFLD:
10758                 case CEE_LDFLDA:
10759                 case CEE_STFLD:
10760                 case CEE_LDSFLD:
10761                 case CEE_LDSFLDA:
10762                 case CEE_STSFLD: {
10763                         MonoClassField *field;
10764 #ifndef DISABLE_REMOTING
10765                         int costs;
10766 #endif
10767                         guint foffset;
10768                         gboolean is_instance;
10769                         int op;
10770                         gpointer addr = NULL;
10771                         gboolean is_special_static;
10772                         MonoType *ftype;
10773                         MonoInst *store_val = NULL;
10774                         MonoInst *thread_ins;
10775
10776                         op = *ip;
10777                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10778                         if (is_instance) {
10779                                 if (op == CEE_STFLD) {
10780                                         CHECK_STACK (2);
10781                                         sp -= 2;
10782                                         store_val = sp [1];
10783                                 } else {
10784                                         CHECK_STACK (1);
10785                                         --sp;
10786                                 }
10787                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10788                                         UNVERIFIED;
10789                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10790                                         UNVERIFIED;
10791                         } else {
10792                                 if (op == CEE_STSFLD) {
10793                                         CHECK_STACK (1);
10794                                         sp--;
10795                                         store_val = sp [0];
10796                                 }
10797                         }
10798
10799                         CHECK_OPSIZE (5);
10800                         token = read32 (ip + 1);
10801                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10802                                 field = mono_method_get_wrapper_data (method, token);
10803                                 klass = field->parent;
10804                         }
10805                         else {
10806                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10807                                 CHECK_CFG_ERROR;
10808                         }
10809                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10810                                 FIELD_ACCESS_FAILURE (method, field);
10811                         mono_class_init (klass);
10812
10813                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10814                                 UNVERIFIED;
10815
10816                         /* if the class is Critical then transparent code cannot access it's fields */
10817                         if (!is_instance && mono_security_core_clr_enabled ())
10818                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10819
10820                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10821                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10822                         if (mono_security_core_clr_enabled ())
10823                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10824                         */
10825
10826                         /*
10827                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10828                          * the static case.
10829                          */
10830                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10831                                 switch (op) {
10832                                 case CEE_LDFLD:
10833                                         op = CEE_LDSFLD;
10834                                         break;
10835                                 case CEE_STFLD:
10836                                         op = CEE_STSFLD;
10837                                         break;
10838                                 case CEE_LDFLDA:
10839                                         op = CEE_LDSFLDA;
10840                                         break;
10841                                 default:
10842                                         g_assert_not_reached ();
10843                                 }
10844                                 is_instance = FALSE;
10845                         }
10846
10847                         context_used = mini_class_check_context_used (cfg, klass);
10848
10849                         /* INSTANCE CASE */
10850
10851                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10852                         if (op == CEE_STFLD) {
10853                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10854                                         UNVERIFIED;
10855 #ifndef DISABLE_REMOTING
10856                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10857                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10858                                         MonoInst *iargs [5];
10859
10860                                         GSHAREDVT_FAILURE (op);
10861
10862                                         iargs [0] = sp [0];
10863                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10864                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10865                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10866                                                     field->offset);
10867                                         iargs [4] = sp [1];
10868
10869                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10870                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10871                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10872                                                 CHECK_CFG_EXCEPTION;
10873                                                 g_assert (costs > 0);
10874                                                       
10875                                                 cfg->real_offset += 5;
10876
10877                                                 inline_costs += costs;
10878                                         } else {
10879                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10880                                         }
10881                                 } else
10882 #endif
10883                                 {
10884                                         MonoInst *store;
10885
10886                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10887
10888                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10889                                                 MonoInst *offset_ins;
10890
10891                                                 context_used = mini_class_check_context_used (cfg, klass);
10892
10893                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10894                                                 dreg = alloc_ireg_mp (cfg);
10895                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10896                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10897                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10898                                         } else {
10899                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10900                                         }
10901                                         if (sp [0]->opcode != OP_LDADDR)
10902                                                 store->flags |= MONO_INST_FAULT;
10903
10904                                 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)) {
10905                                         /* insert call to write barrier */
10906                                         MonoInst *ptr;
10907                                         int dreg;
10908
10909                                         dreg = alloc_ireg_mp (cfg);
10910                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10911                                         emit_write_barrier (cfg, ptr, sp [1]);
10912                                 }
10913
10914                                         store->flags |= ins_flag;
10915                                 }
10916                                 ins_flag = 0;
10917                                 ip += 5;
10918                                 break;
10919                         }
10920
10921 #ifndef DISABLE_REMOTING
10922                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10923                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10924                                 MonoInst *iargs [4];
10925
10926                                 GSHAREDVT_FAILURE (op);
10927
10928                                 iargs [0] = sp [0];
10929                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10930                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10931                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10932                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10933                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10934                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10935                                         CHECK_CFG_EXCEPTION;
10936                                         g_assert (costs > 0);
10937                                                       
10938                                         cfg->real_offset += 5;
10939
10940                                         *sp++ = iargs [0];
10941
10942                                         inline_costs += costs;
10943                                 } else {
10944                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10945                                         *sp++ = ins;
10946                                 }
10947                         } else 
10948 #endif
10949                         if (is_instance) {
10950                                 if (sp [0]->type == STACK_VTYPE) {
10951                                         MonoInst *var;
10952
10953                                         /* Have to compute the address of the variable */
10954
10955                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10956                                         if (!var)
10957                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10958                                         else
10959                                                 g_assert (var->klass == klass);
10960                                         
10961                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10962                                         sp [0] = ins;
10963                                 }
10964
10965                                 if (op == CEE_LDFLDA) {
10966                                         if (is_magic_tls_access (field)) {
10967                                                 GSHAREDVT_FAILURE (*ip);
10968                                                 ins = sp [0];
10969                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10970                                         } else {
10971                                                 if (sp [0]->type == STACK_OBJ) {
10972                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10973                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10974                                                 }
10975
10976                                                 dreg = alloc_ireg_mp (cfg);
10977
10978                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10979                                                         MonoInst *offset_ins;
10980
10981                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10982                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10983                                                 } else {
10984                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10985                                                 }
10986                                                 ins->klass = mono_class_from_mono_type (field->type);
10987                                                 ins->type = STACK_MP;
10988                                                 *sp++ = ins;
10989                                         }
10990                                 } else {
10991                                         MonoInst *load;
10992
10993                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10994
10995                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10996                                                 MonoInst *offset_ins;
10997
10998                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10999                                                 dreg = alloc_ireg_mp (cfg);
11000                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11001                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11002                                         } else {
11003                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11004                                         }
11005                                         load->flags |= ins_flag;
11006                                         if (sp [0]->opcode != OP_LDADDR)
11007                                                 load->flags |= MONO_INST_FAULT;
11008                                         *sp++ = load;
11009                                 }
11010                         }
11011
11012                         if (is_instance) {
11013                                 ins_flag = 0;
11014                                 ip += 5;
11015                                 break;
11016                         }
11017
11018                         /* STATIC CASE */
11019
11020                         /*
11021                          * We can only support shared generic static
11022                          * field access on architectures where the
11023                          * trampoline code has been extended to handle
11024                          * the generic class init.
11025                          */
11026 #ifndef MONO_ARCH_VTABLE_REG
11027                         GENERIC_SHARING_FAILURE (op);
11028 #endif
11029
11030                         context_used = mini_class_check_context_used (cfg, klass);
11031
11032                         ftype = mono_field_get_type (field);
11033
11034                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11035                                 UNVERIFIED;
11036
11037                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11038                          * to be called here.
11039                          */
11040                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11041                                 mono_class_vtable (cfg->domain, klass);
11042                                 CHECK_TYPELOAD (klass);
11043                         }
11044                         mono_domain_lock (cfg->domain);
11045                         if (cfg->domain->special_static_fields)
11046                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11047                         mono_domain_unlock (cfg->domain);
11048
11049                         is_special_static = mono_class_field_is_special_static (field);
11050
11051                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11052                                 thread_ins = mono_get_thread_intrinsic (cfg);
11053                         else
11054                                 thread_ins = NULL;
11055
11056                         /* Generate IR to compute the field address */
11057                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11058                                 /*
11059                                  * Fast access to TLS data
11060                                  * Inline version of get_thread_static_data () in
11061                                  * threads.c.
11062                                  */
11063                                 guint32 offset;
11064                                 int idx, static_data_reg, array_reg, dreg;
11065
11066                                 GSHAREDVT_FAILURE (op);
11067
11068                                 // offset &= 0x7fffffff;
11069                                 // idx = (offset >> 24) - 1;
11070                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
11071                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11072                                 static_data_reg = alloc_ireg (cfg);
11073                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11074
11075                                 if (cfg->compile_aot) {
11076                                         int offset_reg, offset2_reg, idx_reg;
11077
11078                                         /* For TLS variables, this will return the TLS offset */
11079                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11080                                         offset_reg = ins->dreg;
11081                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11082                                         idx_reg = alloc_ireg (cfg);
11083                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
11084                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
11085                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11086                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11087                                         array_reg = alloc_ireg (cfg);
11088                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11089                                         offset2_reg = alloc_ireg (cfg);
11090                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
11091                                         dreg = alloc_ireg (cfg);
11092                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11093                                 } else {
11094                                         offset = (gsize)addr & 0x7fffffff;
11095                                         idx = (offset >> 24) - 1;
11096
11097                                         array_reg = alloc_ireg (cfg);
11098                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11099                                         dreg = alloc_ireg (cfg);
11100                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
11101                                 }
11102                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11103                                         (cfg->compile_aot && is_special_static) ||
11104                                         (context_used && is_special_static)) {
11105                                 MonoInst *iargs [2];
11106
11107                                 g_assert (field->parent);
11108                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11109                                 if (context_used) {
11110                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11111                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11112                                 } else {
11113                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11114                                 }
11115                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11116                         } else if (context_used) {
11117                                 MonoInst *static_data;
11118
11119                                 /*
11120                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11121                                         method->klass->name_space, method->klass->name, method->name,
11122                                         depth, field->offset);
11123                                 */
11124
11125                                 if (mono_class_needs_cctor_run (klass, method))
11126                                         emit_generic_class_init (cfg, klass);
11127
11128                                 /*
11129                                  * The pointer we're computing here is
11130                                  *
11131                                  *   super_info.static_data + field->offset
11132                                  */
11133                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11134                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11135
11136                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
11137                                         MonoInst *offset_ins;
11138
11139                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11140                                         dreg = alloc_ireg_mp (cfg);
11141                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11142                                 } else if (field->offset == 0) {
11143                                         ins = static_data;
11144                                 } else {
11145                                         int addr_reg = mono_alloc_preg (cfg);
11146                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11147                                 }
11148                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11149                                 MonoInst *iargs [2];
11150
11151                                 g_assert (field->parent);
11152                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11153                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11154                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11155                         } else {
11156                                 MonoVTable *vtable = NULL;
11157
11158                                 if (!cfg->compile_aot)
11159                                         vtable = mono_class_vtable (cfg->domain, klass);
11160                                 CHECK_TYPELOAD (klass);
11161
11162                                 if (!addr) {
11163                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11164                                                 if (!(g_slist_find (class_inits, klass))) {
11165                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
11166                                                         if (cfg->verbose_level > 2)
11167                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11168                                                         class_inits = g_slist_prepend (class_inits, klass);
11169                                                 }
11170                                         } else {
11171                                                 if (cfg->run_cctors) {
11172                                                         MonoException *ex;
11173                                                         /* This makes so that inline cannot trigger */
11174                                                         /* .cctors: too many apps depend on them */
11175                                                         /* running with a specific order... */
11176                                                         g_assert (vtable);
11177                                                         if (! vtable->initialized)
11178                                                                 INLINE_FAILURE ("class init");
11179                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11180                                                         if (ex) {
11181                                                                 set_exception_object (cfg, ex);
11182                                                                 goto exception_exit;
11183                                                         }
11184                                                 }
11185                                         }
11186                                         if (cfg->compile_aot)
11187                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11188                                         else {
11189                                                 g_assert (vtable);
11190                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11191                                                 g_assert (addr);
11192                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11193                                         }
11194                                 } else {
11195                                         MonoInst *iargs [1];
11196                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11197                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11198                                 }
11199                         }
11200
11201                         /* Generate IR to do the actual load/store operation */
11202
11203                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11204                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11205                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11206                         }
11207
11208                         if (op == CEE_LDSFLDA) {
11209                                 ins->klass = mono_class_from_mono_type (ftype);
11210                                 ins->type = STACK_PTR;
11211                                 *sp++ = ins;
11212                         } else if (op == CEE_STSFLD) {
11213                                 MonoInst *store;
11214
11215                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11216                                 store->flags |= ins_flag;
11217                         } else {
11218                                 gboolean is_const = FALSE;
11219                                 MonoVTable *vtable = NULL;
11220                                 gpointer addr = NULL;
11221
11222                                 if (!context_used) {
11223                                         vtable = mono_class_vtable (cfg->domain, klass);
11224                                         CHECK_TYPELOAD (klass);
11225                                 }
11226                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11227                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11228                                         int ro_type = ftype->type;
11229                                         if (!addr)
11230                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11231                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11232                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11233                                         }
11234
11235                                         GSHAREDVT_FAILURE (op);
11236
11237                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11238                                         is_const = TRUE;
11239                                         switch (ro_type) {
11240                                         case MONO_TYPE_BOOLEAN:
11241                                         case MONO_TYPE_U1:
11242                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11243                                                 sp++;
11244                                                 break;
11245                                         case MONO_TYPE_I1:
11246                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11247                                                 sp++;
11248                                                 break;                                          
11249                                         case MONO_TYPE_CHAR:
11250                                         case MONO_TYPE_U2:
11251                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11252                                                 sp++;
11253                                                 break;
11254                                         case MONO_TYPE_I2:
11255                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11256                                                 sp++;
11257                                                 break;
11258                                                 break;
11259                                         case MONO_TYPE_I4:
11260                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11261                                                 sp++;
11262                                                 break;                                          
11263                                         case MONO_TYPE_U4:
11264                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11265                                                 sp++;
11266                                                 break;
11267                                         case MONO_TYPE_I:
11268                                         case MONO_TYPE_U:
11269                                         case MONO_TYPE_PTR:
11270                                         case MONO_TYPE_FNPTR:
11271                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11272                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11273                                                 sp++;
11274                                                 break;
11275                                         case MONO_TYPE_STRING:
11276                                         case MONO_TYPE_OBJECT:
11277                                         case MONO_TYPE_CLASS:
11278                                         case MONO_TYPE_SZARRAY:
11279                                         case MONO_TYPE_ARRAY:
11280                                                 if (!mono_gc_is_moving ()) {
11281                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11282                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11283                                                         sp++;
11284                                                 } else {
11285                                                         is_const = FALSE;
11286                                                 }
11287                                                 break;
11288                                         case MONO_TYPE_I8:
11289                                         case MONO_TYPE_U8:
11290                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11291                                                 sp++;
11292                                                 break;
11293                                         case MONO_TYPE_R4:
11294                                         case MONO_TYPE_R8:
11295                                         case MONO_TYPE_VALUETYPE:
11296                                         default:
11297                                                 is_const = FALSE;
11298                                                 break;
11299                                         }
11300                                 }
11301
11302                                 if (!is_const) {
11303                                         MonoInst *load;
11304
11305                                         CHECK_STACK_OVF (1);
11306
11307                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11308                                         load->flags |= ins_flag;
11309                                         ins_flag = 0;
11310                                         *sp++ = load;
11311                                 }
11312                         }
11313
11314                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11315                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11316                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11317                         }
11318
11319                         ins_flag = 0;
11320                         ip += 5;
11321                         break;
11322                 }
11323                 case CEE_STOBJ:
11324                         CHECK_STACK (2);
11325                         sp -= 2;
11326                         CHECK_OPSIZE (5);
11327                         token = read32 (ip + 1);
11328                         klass = mini_get_class (method, token, generic_context);
11329                         CHECK_TYPELOAD (klass);
11330                         if (ins_flag & MONO_INST_VOLATILE) {
11331                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11332                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11333                         }
11334                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11335                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11336                         ins->flags |= ins_flag;
11337                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11338                                         generic_class_is_reference_type (cfg, klass)) {
11339                                 /* insert call to write barrier */
11340                                 emit_write_barrier (cfg, sp [0], sp [1]);
11341                         }
11342                         ins_flag = 0;
11343                         ip += 5;
11344                         inline_costs += 1;
11345                         break;
11346
11347                         /*
11348                          * Array opcodes
11349                          */
11350                 case CEE_NEWARR: {
11351                         MonoInst *len_ins;
11352                         const char *data_ptr;
11353                         int data_size = 0;
11354                         guint32 field_token;
11355
11356                         CHECK_STACK (1);
11357                         --sp;
11358
11359                         CHECK_OPSIZE (5);
11360                         token = read32 (ip + 1);
11361
11362                         klass = mini_get_class (method, token, generic_context);
11363                         CHECK_TYPELOAD (klass);
11364
11365                         context_used = mini_class_check_context_used (cfg, klass);
11366
11367                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11368                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11369                                 ins->sreg1 = sp [0]->dreg;
11370                                 ins->type = STACK_I4;
11371                                 ins->dreg = alloc_ireg (cfg);
11372                                 MONO_ADD_INS (cfg->cbb, ins);
11373                                 *sp = mono_decompose_opcode (cfg, ins, &bblock);
11374                         }
11375
11376                         if (context_used) {
11377                                 MonoInst *args [3];
11378                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11379                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11380
11381                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11382
11383                                 /* vtable */
11384                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11385                                         array_class, MONO_RGCTX_INFO_VTABLE);
11386                                 /* array len */
11387                                 args [1] = sp [0];
11388
11389                                 if (managed_alloc)
11390                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11391                                 else
11392                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11393                         } else {
11394                                 if (cfg->opt & MONO_OPT_SHARED) {
11395                                         /* Decompose now to avoid problems with references to the domainvar */
11396                                         MonoInst *iargs [3];
11397
11398                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11399                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11400                                         iargs [2] = sp [0];
11401
11402                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11403                                 } else {
11404                                         /* Decompose later since it is needed by abcrem */
11405                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11406                                         mono_class_vtable (cfg->domain, array_type);
11407                                         CHECK_TYPELOAD (array_type);
11408
11409                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11410                                         ins->dreg = alloc_ireg_ref (cfg);
11411                                         ins->sreg1 = sp [0]->dreg;
11412                                         ins->inst_newa_class = klass;
11413                                         ins->type = STACK_OBJ;
11414                                         ins->klass = array_type;
11415                                         MONO_ADD_INS (cfg->cbb, ins);
11416                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11417                                         cfg->cbb->has_array_access = TRUE;
11418
11419                                         /* Needed so mono_emit_load_get_addr () gets called */
11420                                         mono_get_got_var (cfg);
11421                                 }
11422                         }
11423
11424                         len_ins = sp [0];
11425                         ip += 5;
11426                         *sp++ = ins;
11427                         inline_costs += 1;
11428
11429                         /* 
11430                          * we inline/optimize the initialization sequence if possible.
11431                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11432                          * for small sizes open code the memcpy
11433                          * ensure the rva field is big enough
11434                          */
11435                         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))) {
11436                                 MonoMethod *memcpy_method = get_memcpy_method ();
11437                                 MonoInst *iargs [3];
11438                                 int add_reg = alloc_ireg_mp (cfg);
11439
11440                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11441                                 if (cfg->compile_aot) {
11442                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11443                                 } else {
11444                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11445                                 }
11446                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11447                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11448                                 ip += 11;
11449                         }
11450
11451                         break;
11452                 }
11453                 case CEE_LDLEN:
11454                         CHECK_STACK (1);
11455                         --sp;
11456                         if (sp [0]->type != STACK_OBJ)
11457                                 UNVERIFIED;
11458
11459                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11460                         ins->dreg = alloc_preg (cfg);
11461                         ins->sreg1 = sp [0]->dreg;
11462                         ins->type = STACK_I4;
11463                         /* This flag will be inherited by the decomposition */
11464                         ins->flags |= MONO_INST_FAULT;
11465                         MONO_ADD_INS (cfg->cbb, ins);
11466                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11467                         cfg->cbb->has_array_access = TRUE;
11468                         ip ++;
11469                         *sp++ = ins;
11470                         break;
11471                 case CEE_LDELEMA:
11472                         CHECK_STACK (2);
11473                         sp -= 2;
11474                         CHECK_OPSIZE (5);
11475                         if (sp [0]->type != STACK_OBJ)
11476                                 UNVERIFIED;
11477
11478                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11479
11480                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11481                         CHECK_TYPELOAD (klass);
11482                         /* we need to make sure that this array is exactly the type it needs
11483                          * to be for correctness. the wrappers are lax with their usage
11484                          * so we need to ignore them here
11485                          */
11486                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11487                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11488                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11489                                 CHECK_TYPELOAD (array_class);
11490                         }
11491
11492                         readonly = FALSE;
11493                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11494                         *sp++ = ins;
11495                         ip += 5;
11496                         break;
11497                 case CEE_LDELEM:
11498                 case CEE_LDELEM_I1:
11499                 case CEE_LDELEM_U1:
11500                 case CEE_LDELEM_I2:
11501                 case CEE_LDELEM_U2:
11502                 case CEE_LDELEM_I4:
11503                 case CEE_LDELEM_U4:
11504                 case CEE_LDELEM_I8:
11505                 case CEE_LDELEM_I:
11506                 case CEE_LDELEM_R4:
11507                 case CEE_LDELEM_R8:
11508                 case CEE_LDELEM_REF: {
11509                         MonoInst *addr;
11510
11511                         CHECK_STACK (2);
11512                         sp -= 2;
11513
11514                         if (*ip == CEE_LDELEM) {
11515                                 CHECK_OPSIZE (5);
11516                                 token = read32 (ip + 1);
11517                                 klass = mini_get_class (method, token, generic_context);
11518                                 CHECK_TYPELOAD (klass);
11519                                 mono_class_init (klass);
11520                         }
11521                         else
11522                                 klass = array_access_to_klass (*ip);
11523
11524                         if (sp [0]->type != STACK_OBJ)
11525                                 UNVERIFIED;
11526
11527                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11528
11529                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11530                                 // FIXME-VT: OP_ICONST optimization
11531                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11532                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11533                                 ins->opcode = OP_LOADV_MEMBASE;
11534                         } else if (sp [1]->opcode == OP_ICONST) {
11535                                 int array_reg = sp [0]->dreg;
11536                                 int index_reg = sp [1]->dreg;
11537                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11538
11539                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11540                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11541                         } else {
11542                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11543                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11544                         }
11545                         *sp++ = ins;
11546                         if (*ip == CEE_LDELEM)
11547                                 ip += 5;
11548                         else
11549                                 ++ip;
11550                         break;
11551                 }
11552                 case CEE_STELEM_I:
11553                 case CEE_STELEM_I1:
11554                 case CEE_STELEM_I2:
11555                 case CEE_STELEM_I4:
11556                 case CEE_STELEM_I8:
11557                 case CEE_STELEM_R4:
11558                 case CEE_STELEM_R8:
11559                 case CEE_STELEM_REF:
11560                 case CEE_STELEM: {
11561                         CHECK_STACK (3);
11562                         sp -= 3;
11563
11564                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11565
11566                         if (*ip == CEE_STELEM) {
11567                                 CHECK_OPSIZE (5);
11568                                 token = read32 (ip + 1);
11569                                 klass = mini_get_class (method, token, generic_context);
11570                                 CHECK_TYPELOAD (klass);
11571                                 mono_class_init (klass);
11572                         }
11573                         else
11574                                 klass = array_access_to_klass (*ip);
11575
11576                         if (sp [0]->type != STACK_OBJ)
11577                                 UNVERIFIED;
11578
11579                         emit_array_store (cfg, klass, sp, TRUE);
11580
11581                         if (*ip == CEE_STELEM)
11582                                 ip += 5;
11583                         else
11584                                 ++ip;
11585                         inline_costs += 1;
11586                         break;
11587                 }
11588                 case CEE_CKFINITE: {
11589                         CHECK_STACK (1);
11590                         --sp;
11591
11592                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11593                         ins->sreg1 = sp [0]->dreg;
11594                         ins->dreg = alloc_freg (cfg);
11595                         ins->type = STACK_R8;
11596                         MONO_ADD_INS (bblock, ins);
11597
11598                         *sp++ = mono_decompose_opcode (cfg, ins, &bblock);
11599
11600                         ++ip;
11601                         break;
11602                 }
11603                 case CEE_REFANYVAL: {
11604                         MonoInst *src_var, *src;
11605
11606                         int klass_reg = alloc_preg (cfg);
11607                         int dreg = alloc_preg (cfg);
11608
11609                         GSHAREDVT_FAILURE (*ip);
11610
11611                         CHECK_STACK (1);
11612                         MONO_INST_NEW (cfg, ins, *ip);
11613                         --sp;
11614                         CHECK_OPSIZE (5);
11615                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11616                         CHECK_TYPELOAD (klass);
11617
11618                         context_used = mini_class_check_context_used (cfg, klass);
11619
11620                         // FIXME:
11621                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11622                         if (!src_var)
11623                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11624                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11625                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11626
11627                         if (context_used) {
11628                                 MonoInst *klass_ins;
11629
11630                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11631                                                 klass, MONO_RGCTX_INFO_KLASS);
11632
11633                                 // FIXME:
11634                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11635                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11636                         } else {
11637                                 mini_emit_class_check (cfg, klass_reg, klass);
11638                         }
11639                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11640                         ins->type = STACK_MP;
11641                         *sp++ = ins;
11642                         ip += 5;
11643                         break;
11644                 }
11645                 case CEE_MKREFANY: {
11646                         MonoInst *loc, *addr;
11647
11648                         GSHAREDVT_FAILURE (*ip);
11649
11650                         CHECK_STACK (1);
11651                         MONO_INST_NEW (cfg, ins, *ip);
11652                         --sp;
11653                         CHECK_OPSIZE (5);
11654                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11655                         CHECK_TYPELOAD (klass);
11656
11657                         context_used = mini_class_check_context_used (cfg, klass);
11658
11659                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11660                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11661
11662                         if (context_used) {
11663                                 MonoInst *const_ins;
11664                                 int type_reg = alloc_preg (cfg);
11665
11666                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11667                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11668                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11669                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11670                         } else if (cfg->compile_aot) {
11671                                 int const_reg = alloc_preg (cfg);
11672                                 int type_reg = alloc_preg (cfg);
11673
11674                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11675                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11676                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11677                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11678                         } else {
11679                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11680                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11681                         }
11682                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11683
11684                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11685                         ins->type = STACK_VTYPE;
11686                         ins->klass = mono_defaults.typed_reference_class;
11687                         *sp++ = ins;
11688                         ip += 5;
11689                         break;
11690                 }
11691                 case CEE_LDTOKEN: {
11692                         gpointer handle;
11693                         MonoClass *handle_class;
11694
11695                         CHECK_STACK_OVF (1);
11696
11697                         CHECK_OPSIZE (5);
11698                         n = read32 (ip + 1);
11699
11700                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11701                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11702                                 handle = mono_method_get_wrapper_data (method, n);
11703                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11704                                 if (handle_class == mono_defaults.typehandle_class)
11705                                         handle = &((MonoClass*)handle)->byval_arg;
11706                         }
11707                         else {
11708                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11709                                 CHECK_CFG_ERROR;
11710                         }
11711                         if (!handle)
11712                                 LOAD_ERROR;
11713                         mono_class_init (handle_class);
11714                         if (cfg->generic_sharing_context) {
11715                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11716                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11717                                         /* This case handles ldtoken
11718                                            of an open type, like for
11719                                            typeof(Gen<>). */
11720                                         context_used = 0;
11721                                 } else if (handle_class == mono_defaults.typehandle_class) {
11722                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11723                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11724                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11725                                 else if (handle_class == mono_defaults.methodhandle_class)
11726                                         context_used = mini_method_check_context_used (cfg, handle);
11727                                 else
11728                                         g_assert_not_reached ();
11729                         }
11730
11731                         if ((cfg->opt & MONO_OPT_SHARED) &&
11732                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11733                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11734                                 MonoInst *addr, *vtvar, *iargs [3];
11735                                 int method_context_used;
11736
11737                                 method_context_used = mini_method_check_context_used (cfg, method);
11738
11739                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11740
11741                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11742                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11743                                 if (method_context_used) {
11744                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11745                                                 method, MONO_RGCTX_INFO_METHOD);
11746                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11747                                 } else {
11748                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11749                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11750                                 }
11751                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11752
11753                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11754
11755                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11756                         } else {
11757                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11758                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11759                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11760                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11761                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11762                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11763
11764                                         mono_class_init (tclass);
11765                                         if (context_used) {
11766                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11767                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11768                                         } else if (cfg->compile_aot) {
11769                                                 if (method->wrapper_type) {
11770                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11771                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11772                                                                 /* Special case for static synchronized wrappers */
11773                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11774                                                         } else {
11775                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11776                                                                 /* FIXME: n is not a normal token */
11777                                                                 DISABLE_AOT (cfg);
11778                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11779                                                         }
11780                                                 } else {
11781                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11782                                                 }
11783                                         } else {
11784                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11785                                         }
11786                                         ins->type = STACK_OBJ;
11787                                         ins->klass = cmethod->klass;
11788                                         ip += 5;
11789                                 } else {
11790                                         MonoInst *addr, *vtvar;
11791
11792                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11793
11794                                         if (context_used) {
11795                                                 if (handle_class == mono_defaults.typehandle_class) {
11796                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11797                                                                         mono_class_from_mono_type (handle),
11798                                                                         MONO_RGCTX_INFO_TYPE);
11799                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11800                                                         ins = emit_get_rgctx_method (cfg, context_used,
11801                                                                         handle, MONO_RGCTX_INFO_METHOD);
11802                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11803                                                         ins = emit_get_rgctx_field (cfg, context_used,
11804                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11805                                                 } else {
11806                                                         g_assert_not_reached ();
11807                                                 }
11808                                         } else if (cfg->compile_aot) {
11809                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11810                                         } else {
11811                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11812                                         }
11813                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11814                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11815                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11816                                 }
11817                         }
11818
11819                         *sp++ = ins;
11820                         ip += 5;
11821                         break;
11822                 }
11823                 case CEE_THROW:
11824                         CHECK_STACK (1);
11825                         MONO_INST_NEW (cfg, ins, OP_THROW);
11826                         --sp;
11827                         ins->sreg1 = sp [0]->dreg;
11828                         ip++;
11829                         bblock->out_of_line = TRUE;
11830                         MONO_ADD_INS (bblock, ins);
11831                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11832                         MONO_ADD_INS (bblock, ins);
11833                         sp = stack_start;
11834                         
11835                         link_bblock (cfg, bblock, end_bblock);
11836                         start_new_bblock = 1;
11837                         break;
11838                 case CEE_ENDFINALLY:
11839                         /* mono_save_seq_point_info () depends on this */
11840                         if (sp != stack_start)
11841                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11842                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11843                         MONO_ADD_INS (bblock, ins);
11844                         ip++;
11845                         start_new_bblock = 1;
11846
11847                         /*
11848                          * Control will leave the method so empty the stack, otherwise
11849                          * the next basic block will start with a nonempty stack.
11850                          */
11851                         while (sp != stack_start) {
11852                                 sp--;
11853                         }
11854                         break;
11855                 case CEE_LEAVE:
11856                 case CEE_LEAVE_S: {
11857                         GList *handlers;
11858
11859                         if (*ip == CEE_LEAVE) {
11860                                 CHECK_OPSIZE (5);
11861                                 target = ip + 5 + (gint32)read32(ip + 1);
11862                         } else {
11863                                 CHECK_OPSIZE (2);
11864                                 target = ip + 2 + (signed char)(ip [1]);
11865                         }
11866
11867                         /* empty the stack */
11868                         while (sp != stack_start) {
11869                                 sp--;
11870                         }
11871
11872                         /* 
11873                          * If this leave statement is in a catch block, check for a
11874                          * pending exception, and rethrow it if necessary.
11875                          * We avoid doing this in runtime invoke wrappers, since those are called
11876                          * by native code which excepts the wrapper to catch all exceptions.
11877                          */
11878                         for (i = 0; i < header->num_clauses; ++i) {
11879                                 MonoExceptionClause *clause = &header->clauses [i];
11880
11881                                 /* 
11882                                  * Use <= in the final comparison to handle clauses with multiple
11883                                  * leave statements, like in bug #78024.
11884                                  * The ordering of the exception clauses guarantees that we find the
11885                                  * innermost clause.
11886                                  */
11887                                 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) {
11888                                         MonoInst *exc_ins;
11889                                         MonoBasicBlock *dont_throw;
11890
11891                                         /*
11892                                           MonoInst *load;
11893
11894                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11895                                         */
11896
11897                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11898
11899                                         NEW_BBLOCK (cfg, dont_throw);
11900
11901                                         /*
11902                                          * Currently, we always rethrow the abort exception, despite the 
11903                                          * fact that this is not correct. See thread6.cs for an example. 
11904                                          * But propagating the abort exception is more important than 
11905                                          * getting the sematics right.
11906                                          */
11907                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11908                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11909                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11910
11911                                         MONO_START_BB (cfg, dont_throw);
11912                                         bblock = cfg->cbb;
11913                                 }
11914                         }
11915
11916                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11917                                 GList *tmp;
11918                                 MonoExceptionClause *clause;
11919
11920                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11921                                         clause = tmp->data;
11922                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11923                                         g_assert (tblock);
11924                                         link_bblock (cfg, bblock, tblock);
11925                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11926                                         ins->inst_target_bb = tblock;
11927                                         ins->inst_eh_block = clause;
11928                                         MONO_ADD_INS (bblock, ins);
11929                                         bblock->has_call_handler = 1;
11930                                         if (COMPILE_LLVM (cfg)) {
11931                                                 MonoBasicBlock *target_bb;
11932
11933                                                 /* 
11934                                                  * Link the finally bblock with the target, since it will
11935                                                  * conceptually branch there.
11936                                                  * FIXME: Have to link the bblock containing the endfinally.
11937                                                  */
11938                                                 GET_BBLOCK (cfg, target_bb, target);
11939                                                 link_bblock (cfg, tblock, target_bb);
11940                                         }
11941                                 }
11942                                 g_list_free (handlers);
11943                         } 
11944
11945                         MONO_INST_NEW (cfg, ins, OP_BR);
11946                         MONO_ADD_INS (bblock, ins);
11947                         GET_BBLOCK (cfg, tblock, target);
11948                         link_bblock (cfg, bblock, tblock);
11949                         ins->inst_target_bb = tblock;
11950                         start_new_bblock = 1;
11951
11952                         if (*ip == CEE_LEAVE)
11953                                 ip += 5;
11954                         else
11955                                 ip += 2;
11956
11957                         break;
11958                 }
11959
11960                         /*
11961                          * Mono specific opcodes
11962                          */
11963                 case MONO_CUSTOM_PREFIX: {
11964
11965                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11966
11967                         CHECK_OPSIZE (2);
11968                         switch (ip [1]) {
11969                         case CEE_MONO_ICALL: {
11970                                 gpointer func;
11971                                 MonoJitICallInfo *info;
11972
11973                                 token = read32 (ip + 2);
11974                                 func = mono_method_get_wrapper_data (method, token);
11975                                 info = mono_find_jit_icall_by_addr (func);
11976                                 if (!info)
11977                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11978                                 g_assert (info);
11979
11980                                 CHECK_STACK (info->sig->param_count);
11981                                 sp -= info->sig->param_count;
11982
11983                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11984                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11985                                         *sp++ = ins;
11986
11987                                 ip += 6;
11988                                 inline_costs += 10 * num_calls++;
11989
11990                                 break;
11991                         }
11992                         case CEE_MONO_LDPTR: {
11993                                 gpointer ptr;
11994
11995                                 CHECK_STACK_OVF (1);
11996                                 CHECK_OPSIZE (6);
11997                                 token = read32 (ip + 2);
11998
11999                                 ptr = mono_method_get_wrapper_data (method, token);
12000                                 /* FIXME: Generalize this */
12001                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
12002                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12003                                         *sp++ = ins;
12004                                         ip += 6;
12005                                         break;
12006                                 }
12007                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12008                                 *sp++ = ins;
12009                                 ip += 6;
12010                                 inline_costs += 10 * num_calls++;
12011                                 /* Can't embed random pointers into AOT code */
12012                                 DISABLE_AOT (cfg);
12013                                 break;
12014                         }
12015                         case CEE_MONO_JIT_ICALL_ADDR: {
12016                                 MonoJitICallInfo *callinfo;
12017                                 gpointer ptr;
12018
12019                                 CHECK_STACK_OVF (1);
12020                                 CHECK_OPSIZE (6);
12021                                 token = read32 (ip + 2);
12022
12023                                 ptr = mono_method_get_wrapper_data (method, token);
12024                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12025                                 g_assert (callinfo);
12026                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12027                                 *sp++ = ins;
12028                                 ip += 6;
12029                                 inline_costs += 10 * num_calls++;
12030                                 break;
12031                         }
12032                         case CEE_MONO_ICALL_ADDR: {
12033                                 MonoMethod *cmethod;
12034                                 gpointer ptr;
12035
12036                                 CHECK_STACK_OVF (1);
12037                                 CHECK_OPSIZE (6);
12038                                 token = read32 (ip + 2);
12039
12040                                 cmethod = mono_method_get_wrapper_data (method, token);
12041
12042                                 if (cfg->compile_aot) {
12043                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12044                                 } else {
12045                                         ptr = mono_lookup_internal_call (cmethod);
12046                                         g_assert (ptr);
12047                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12048                                 }
12049                                 *sp++ = ins;
12050                                 ip += 6;
12051                                 break;
12052                         }
12053                         case CEE_MONO_VTADDR: {
12054                                 MonoInst *src_var, *src;
12055
12056                                 CHECK_STACK (1);
12057                                 --sp;
12058
12059                                 // FIXME:
12060                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12061                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12062                                 *sp++ = src;
12063                                 ip += 2;
12064                                 break;
12065                         }
12066                         case CEE_MONO_NEWOBJ: {
12067                                 MonoInst *iargs [2];
12068
12069                                 CHECK_STACK_OVF (1);
12070                                 CHECK_OPSIZE (6);
12071                                 token = read32 (ip + 2);
12072                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12073                                 mono_class_init (klass);
12074                                 NEW_DOMAINCONST (cfg, iargs [0]);
12075                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12076                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12077                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12078                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12079                                 ip += 6;
12080                                 inline_costs += 10 * num_calls++;
12081                                 break;
12082                         }
12083                         case CEE_MONO_OBJADDR:
12084                                 CHECK_STACK (1);
12085                                 --sp;
12086                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12087                                 ins->dreg = alloc_ireg_mp (cfg);
12088                                 ins->sreg1 = sp [0]->dreg;
12089                                 ins->type = STACK_MP;
12090                                 MONO_ADD_INS (cfg->cbb, ins);
12091                                 *sp++ = ins;
12092                                 ip += 2;
12093                                 break;
12094                         case CEE_MONO_LDNATIVEOBJ:
12095                                 /*
12096                                  * Similar to LDOBJ, but instead load the unmanaged 
12097                                  * representation of the vtype to the stack.
12098                                  */
12099                                 CHECK_STACK (1);
12100                                 CHECK_OPSIZE (6);
12101                                 --sp;
12102                                 token = read32 (ip + 2);
12103                                 klass = mono_method_get_wrapper_data (method, token);
12104                                 g_assert (klass->valuetype);
12105                                 mono_class_init (klass);
12106
12107                                 {
12108                                         MonoInst *src, *dest, *temp;
12109
12110                                         src = sp [0];
12111                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12112                                         temp->backend.is_pinvoke = 1;
12113                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12114                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12115
12116                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12117                                         dest->type = STACK_VTYPE;
12118                                         dest->klass = klass;
12119
12120                                         *sp ++ = dest;
12121                                         ip += 6;
12122                                 }
12123                                 break;
12124                         case CEE_MONO_RETOBJ: {
12125                                 /*
12126                                  * Same as RET, but return the native representation of a vtype
12127                                  * to the caller.
12128                                  */
12129                                 g_assert (cfg->ret);
12130                                 g_assert (mono_method_signature (method)->pinvoke); 
12131                                 CHECK_STACK (1);
12132                                 --sp;
12133                                 
12134                                 CHECK_OPSIZE (6);
12135                                 token = read32 (ip + 2);    
12136                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12137
12138                                 if (!cfg->vret_addr) {
12139                                         g_assert (cfg->ret_var_is_local);
12140
12141                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12142                                 } else {
12143                                         EMIT_NEW_RETLOADA (cfg, ins);
12144                                 }
12145                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12146                                 
12147                                 if (sp != stack_start)
12148                                         UNVERIFIED;
12149                                 
12150                                 MONO_INST_NEW (cfg, ins, OP_BR);
12151                                 ins->inst_target_bb = end_bblock;
12152                                 MONO_ADD_INS (bblock, ins);
12153                                 link_bblock (cfg, bblock, end_bblock);
12154                                 start_new_bblock = 1;
12155                                 ip += 6;
12156                                 break;
12157                         }
12158                         case CEE_MONO_CISINST:
12159                         case CEE_MONO_CCASTCLASS: {
12160                                 int token;
12161                                 CHECK_STACK (1);
12162                                 --sp;
12163                                 CHECK_OPSIZE (6);
12164                                 token = read32 (ip + 2);
12165                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12166                                 if (ip [1] == CEE_MONO_CISINST)
12167                                         ins = handle_cisinst (cfg, klass, sp [0]);
12168                                 else
12169                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12170                                 bblock = cfg->cbb;
12171                                 *sp++ = ins;
12172                                 ip += 6;
12173                                 break;
12174                         }
12175                         case CEE_MONO_SAVE_LMF:
12176                         case CEE_MONO_RESTORE_LMF:
12177 #ifdef MONO_ARCH_HAVE_LMF_OPS
12178                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
12179                                 MONO_ADD_INS (bblock, ins);
12180                                 cfg->need_lmf_area = TRUE;
12181 #endif
12182                                 ip += 2;
12183                                 break;
12184                         case CEE_MONO_CLASSCONST:
12185                                 CHECK_STACK_OVF (1);
12186                                 CHECK_OPSIZE (6);
12187                                 token = read32 (ip + 2);
12188                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12189                                 *sp++ = ins;
12190                                 ip += 6;
12191                                 inline_costs += 10 * num_calls++;
12192                                 break;
12193                         case CEE_MONO_NOT_TAKEN:
12194                                 bblock->out_of_line = TRUE;
12195                                 ip += 2;
12196                                 break;
12197                         case CEE_MONO_TLS: {
12198                                 int key;
12199
12200                                 CHECK_STACK_OVF (1);
12201                                 CHECK_OPSIZE (6);
12202                                 key = (gint32)read32 (ip + 2);
12203                                 g_assert (key < TLS_KEY_NUM);
12204
12205                                 ins = mono_create_tls_get (cfg, key);
12206                                 if (!ins) {
12207                                         if (cfg->compile_aot) {
12208                                                 DISABLE_AOT (cfg);
12209                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12210                                                 ins->dreg = alloc_preg (cfg);
12211                                                 ins->type = STACK_PTR;
12212                                         } else {
12213                                                 g_assert_not_reached ();
12214                                         }
12215                                 }
12216                                 ins->type = STACK_PTR;
12217                                 MONO_ADD_INS (bblock, ins);
12218                                 *sp++ = ins;
12219                                 ip += 6;
12220                                 break;
12221                         }
12222                         case CEE_MONO_DYN_CALL: {
12223                                 MonoCallInst *call;
12224
12225                                 /* It would be easier to call a trampoline, but that would put an
12226                                  * extra frame on the stack, confusing exception handling. So
12227                                  * implement it inline using an opcode for now.
12228                                  */
12229
12230                                 if (!cfg->dyn_call_var) {
12231                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12232                                         /* prevent it from being register allocated */
12233                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12234                                 }
12235
12236                                 /* Has to use a call inst since it local regalloc expects it */
12237                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12238                                 ins = (MonoInst*)call;
12239                                 sp -= 2;
12240                                 ins->sreg1 = sp [0]->dreg;
12241                                 ins->sreg2 = sp [1]->dreg;
12242                                 MONO_ADD_INS (bblock, ins);
12243
12244                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
12245
12246                                 ip += 2;
12247                                 inline_costs += 10 * num_calls++;
12248
12249                                 break;
12250                         }
12251                         case CEE_MONO_MEMORY_BARRIER: {
12252                                 CHECK_OPSIZE (6);
12253                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12254                                 ip += 6;
12255                                 break;
12256                         }
12257                         case CEE_MONO_JIT_ATTACH: {
12258                                 MonoInst *args [16], *domain_ins;
12259                                 MonoInst *ad_ins, *jit_tls_ins;
12260                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12261
12262                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12263
12264                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12265                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12266
12267                                 ad_ins = mono_get_domain_intrinsic (cfg);
12268                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12269
12270                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
12271                                         NEW_BBLOCK (cfg, next_bb);
12272                                         NEW_BBLOCK (cfg, call_bb);
12273
12274                                         if (cfg->compile_aot) {
12275                                                 /* AOT code is only used in the root domain */
12276                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12277                                         } else {
12278                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12279                                         }
12280                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12281                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12282                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12283
12284                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12285                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12286                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12287
12288                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12289                                         MONO_START_BB (cfg, call_bb);
12290                                 }
12291
12292                                 if (cfg->compile_aot) {
12293                                         /* AOT code is only used in the root domain */
12294                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12295                                 } else {
12296                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12297                                 }
12298                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12299                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12300
12301                                 if (next_bb) {
12302                                         MONO_START_BB (cfg, next_bb);
12303                                         bblock = cfg->cbb;
12304                                 }
12305                                 ip += 2;
12306                                 break;
12307                         }
12308                         case CEE_MONO_JIT_DETACH: {
12309                                 MonoInst *args [16];
12310
12311                                 /* Restore the original domain */
12312                                 dreg = alloc_ireg (cfg);
12313                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12314                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12315                                 ip += 2;
12316                                 break;
12317                         }
12318                         default:
12319                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12320                                 break;
12321                         }
12322                         break;
12323                 }
12324
12325                 case CEE_PREFIX1: {
12326                         CHECK_OPSIZE (2);
12327                         switch (ip [1]) {
12328                         case CEE_ARGLIST: {
12329                                 /* somewhat similar to LDTOKEN */
12330                                 MonoInst *addr, *vtvar;
12331                                 CHECK_STACK_OVF (1);
12332                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12333
12334                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12335                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12336
12337                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12338                                 ins->type = STACK_VTYPE;
12339                                 ins->klass = mono_defaults.argumenthandle_class;
12340                                 *sp++ = ins;
12341                                 ip += 2;
12342                                 break;
12343                         }
12344                         case CEE_CEQ:
12345                         case CEE_CGT:
12346                         case CEE_CGT_UN:
12347                         case CEE_CLT:
12348                         case CEE_CLT_UN: {
12349                                 MonoInst *cmp, *arg1, *arg2;
12350
12351                                 CHECK_STACK (2);
12352                                 sp -= 2;
12353                                 arg1 = sp [0];
12354                                 arg2 = sp [1];
12355
12356                                 /*
12357                                  * The following transforms:
12358                                  *    CEE_CEQ    into OP_CEQ
12359                                  *    CEE_CGT    into OP_CGT
12360                                  *    CEE_CGT_UN into OP_CGT_UN
12361                                  *    CEE_CLT    into OP_CLT
12362                                  *    CEE_CLT_UN into OP_CLT_UN
12363                                  */
12364                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12365
12366                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12367                                 cmp->sreg1 = arg1->dreg;
12368                                 cmp->sreg2 = arg2->dreg;
12369                                 type_from_op (cfg, cmp, arg1, arg2);
12370                                 CHECK_TYPE (cmp);
12371                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12372                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12373                                         cmp->opcode = OP_LCOMPARE;
12374                                 else if (arg1->type == STACK_R4)
12375                                         cmp->opcode = OP_RCOMPARE;
12376                                 else if (arg1->type == STACK_R8)
12377                                         cmp->opcode = OP_FCOMPARE;
12378                                 else
12379                                         cmp->opcode = OP_ICOMPARE;
12380                                 MONO_ADD_INS (bblock, cmp);
12381                                 ins->type = STACK_I4;
12382                                 ins->dreg = alloc_dreg (cfg, ins->type);
12383                                 type_from_op (cfg, ins, arg1, arg2);
12384
12385                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12386                                         /*
12387                                          * The backends expect the fceq opcodes to do the
12388                                          * comparison too.
12389                                          */
12390                                         ins->sreg1 = cmp->sreg1;
12391                                         ins->sreg2 = cmp->sreg2;
12392                                         NULLIFY_INS (cmp);
12393                                 }
12394                                 MONO_ADD_INS (bblock, ins);
12395                                 *sp++ = ins;
12396                                 ip += 2;
12397                                 break;
12398                         }
12399                         case CEE_LDFTN: {
12400                                 MonoInst *argconst;
12401                                 MonoMethod *cil_method;
12402
12403                                 CHECK_STACK_OVF (1);
12404                                 CHECK_OPSIZE (6);
12405                                 n = read32 (ip + 2);
12406                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12407                                 if (!cmethod || mono_loader_get_last_error ())
12408                                         LOAD_ERROR;
12409                                 mono_class_init (cmethod->klass);
12410
12411                                 mono_save_token_info (cfg, image, n, cmethod);
12412
12413                                 context_used = mini_method_check_context_used (cfg, cmethod);
12414
12415                                 cil_method = cmethod;
12416                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12417                                         METHOD_ACCESS_FAILURE (method, cil_method);
12418
12419                                 if (mono_security_cas_enabled ()) {
12420                                         if (check_linkdemand (cfg, method, cmethod))
12421                                                 INLINE_FAILURE ("linkdemand");
12422                                         CHECK_CFG_EXCEPTION;
12423                                 } else if (mono_security_core_clr_enabled ()) {
12424                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12425                                 }
12426
12427                                 /* 
12428                                  * Optimize the common case of ldftn+delegate creation
12429                                  */
12430                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12431                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12432                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12433                                                 MonoInst *target_ins, *handle_ins;
12434                                                 MonoMethod *invoke;
12435                                                 int invoke_context_used;
12436
12437                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12438                                                 if (!invoke || !mono_method_signature (invoke))
12439                                                         LOAD_ERROR;
12440
12441                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12442
12443                                                 target_ins = sp [-1];
12444
12445                                                 if (mono_security_core_clr_enabled ())
12446                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12447
12448                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12449                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12450                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12451                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12452                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12453                                                         }
12454                                                 }
12455
12456 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12457                                                 /* FIXME: SGEN support */
12458                                                 if (invoke_context_used == 0) {
12459                                                         ip += 6;
12460                                                         if (cfg->verbose_level > 3)
12461                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12462                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12463                                                                 sp --;
12464                                                                 *sp = handle_ins;
12465                                                                 CHECK_CFG_EXCEPTION;
12466                                                                 ip += 5;
12467                                                                 sp ++;
12468                                                                 break;
12469                                                         }
12470                                                         ip -= 6;
12471                                                 }
12472 #endif
12473                                         }
12474                                 }
12475
12476                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12477                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12478                                 *sp++ = ins;
12479                                 
12480                                 ip += 6;
12481                                 inline_costs += 10 * num_calls++;
12482                                 break;
12483                         }
12484                         case CEE_LDVIRTFTN: {
12485                                 MonoInst *args [2];
12486
12487                                 CHECK_STACK (1);
12488                                 CHECK_OPSIZE (6);
12489                                 n = read32 (ip + 2);
12490                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12491                                 if (!cmethod || mono_loader_get_last_error ())
12492                                         LOAD_ERROR;
12493                                 mono_class_init (cmethod->klass);
12494  
12495                                 context_used = mini_method_check_context_used (cfg, cmethod);
12496
12497                                 if (mono_security_cas_enabled ()) {
12498                                         if (check_linkdemand (cfg, method, cmethod))
12499                                                 INLINE_FAILURE ("linkdemand");
12500                                         CHECK_CFG_EXCEPTION;
12501                                 } else if (mono_security_core_clr_enabled ()) {
12502                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12503                                 }
12504
12505                                 /*
12506                                  * Optimize the common case of ldvirtftn+delegate creation
12507                                  */
12508                                 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)) {
12509                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12510                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12511                                                 MonoInst *target_ins, *handle_ins;
12512                                                 MonoMethod *invoke;
12513                                                 int invoke_context_used;
12514
12515                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12516                                                 if (!invoke || !mono_method_signature (invoke))
12517                                                         LOAD_ERROR;
12518
12519                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12520
12521                                                 target_ins = sp [-1];
12522
12523                                                 if (mono_security_core_clr_enabled ())
12524                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12525
12526 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12527                                                 /* FIXME: SGEN support */
12528                                                 if (invoke_context_used == 0) {
12529                                                         ip += 6;
12530                                                         if (cfg->verbose_level > 3)
12531                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12532                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12533                                                                 sp -= 2;
12534                                                                 *sp = handle_ins;
12535                                                                 CHECK_CFG_EXCEPTION;
12536                                                                 ip += 5;
12537                                                                 sp ++;
12538                                                                 break;
12539                                                         }
12540                                                         ip -= 6;
12541                                                 }
12542 #endif
12543                                         }
12544                                 }
12545
12546                                 --sp;
12547                                 args [0] = *sp;
12548
12549                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12550                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12551
12552                                 if (context_used)
12553                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12554                                 else
12555                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12556
12557                                 ip += 6;
12558                                 inline_costs += 10 * num_calls++;
12559                                 break;
12560                         }
12561                         case CEE_LDARG:
12562                                 CHECK_STACK_OVF (1);
12563                                 CHECK_OPSIZE (4);
12564                                 n = read16 (ip + 2);
12565                                 CHECK_ARG (n);
12566                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12567                                 *sp++ = ins;
12568                                 ip += 4;
12569                                 break;
12570                         case CEE_LDARGA:
12571                                 CHECK_STACK_OVF (1);
12572                                 CHECK_OPSIZE (4);
12573                                 n = read16 (ip + 2);
12574                                 CHECK_ARG (n);
12575                                 NEW_ARGLOADA (cfg, ins, n);
12576                                 MONO_ADD_INS (cfg->cbb, ins);
12577                                 *sp++ = ins;
12578                                 ip += 4;
12579                                 break;
12580                         case CEE_STARG:
12581                                 CHECK_STACK (1);
12582                                 --sp;
12583                                 CHECK_OPSIZE (4);
12584                                 n = read16 (ip + 2);
12585                                 CHECK_ARG (n);
12586                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12587                                         UNVERIFIED;
12588                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12589                                 ip += 4;
12590                                 break;
12591                         case CEE_LDLOC:
12592                                 CHECK_STACK_OVF (1);
12593                                 CHECK_OPSIZE (4);
12594                                 n = read16 (ip + 2);
12595                                 CHECK_LOCAL (n);
12596                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12597                                 *sp++ = ins;
12598                                 ip += 4;
12599                                 break;
12600                         case CEE_LDLOCA: {
12601                                 unsigned char *tmp_ip;
12602                                 CHECK_STACK_OVF (1);
12603                                 CHECK_OPSIZE (4);
12604                                 n = read16 (ip + 2);
12605                                 CHECK_LOCAL (n);
12606
12607                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12608                                         ip = tmp_ip;
12609                                         inline_costs += 1;
12610                                         break;
12611                                 }                       
12612                                 
12613                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12614                                 *sp++ = ins;
12615                                 ip += 4;
12616                                 break;
12617                         }
12618                         case CEE_STLOC:
12619                                 CHECK_STACK (1);
12620                                 --sp;
12621                                 CHECK_OPSIZE (4);
12622                                 n = read16 (ip + 2);
12623                                 CHECK_LOCAL (n);
12624                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12625                                         UNVERIFIED;
12626                                 emit_stloc_ir (cfg, sp, header, n);
12627                                 ip += 4;
12628                                 inline_costs += 1;
12629                                 break;
12630                         case CEE_LOCALLOC:
12631                                 CHECK_STACK (1);
12632                                 --sp;
12633                                 if (sp != stack_start) 
12634                                         UNVERIFIED;
12635                                 if (cfg->method != method) 
12636                                         /* 
12637                                          * Inlining this into a loop in a parent could lead to 
12638                                          * stack overflows which is different behavior than the
12639                                          * non-inlined case, thus disable inlining in this case.
12640                                          */
12641                                         INLINE_FAILURE("localloc");
12642
12643                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12644                                 ins->dreg = alloc_preg (cfg);
12645                                 ins->sreg1 = sp [0]->dreg;
12646                                 ins->type = STACK_PTR;
12647                                 MONO_ADD_INS (cfg->cbb, ins);
12648
12649                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12650                                 if (init_locals)
12651                                         ins->flags |= MONO_INST_INIT;
12652
12653                                 *sp++ = ins;
12654                                 ip += 2;
12655                                 break;
12656                         case CEE_ENDFILTER: {
12657                                 MonoExceptionClause *clause, *nearest;
12658                                 int cc, nearest_num;
12659
12660                                 CHECK_STACK (1);
12661                                 --sp;
12662                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12663                                         UNVERIFIED;
12664                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12665                                 ins->sreg1 = (*sp)->dreg;
12666                                 MONO_ADD_INS (bblock, ins);
12667                                 start_new_bblock = 1;
12668                                 ip += 2;
12669
12670                                 nearest = NULL;
12671                                 nearest_num = 0;
12672                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12673                                         clause = &header->clauses [cc];
12674                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12675                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12676                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12677                                                 nearest = clause;
12678                                                 nearest_num = cc;
12679                                         }
12680                                 }
12681                                 g_assert (nearest);
12682                                 if ((ip - header->code) != nearest->handler_offset)
12683                                         UNVERIFIED;
12684
12685                                 break;
12686                         }
12687                         case CEE_UNALIGNED_:
12688                                 ins_flag |= MONO_INST_UNALIGNED;
12689                                 /* FIXME: record alignment? we can assume 1 for now */
12690                                 CHECK_OPSIZE (3);
12691                                 ip += 3;
12692                                 break;
12693                         case CEE_VOLATILE_:
12694                                 ins_flag |= MONO_INST_VOLATILE;
12695                                 ip += 2;
12696                                 break;
12697                         case CEE_TAIL_:
12698                                 ins_flag   |= MONO_INST_TAILCALL;
12699                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12700                                 /* Can't inline tail calls at this time */
12701                                 inline_costs += 100000;
12702                                 ip += 2;
12703                                 break;
12704                         case CEE_INITOBJ:
12705                                 CHECK_STACK (1);
12706                                 --sp;
12707                                 CHECK_OPSIZE (6);
12708                                 token = read32 (ip + 2);
12709                                 klass = mini_get_class (method, token, generic_context);
12710                                 CHECK_TYPELOAD (klass);
12711                                 if (generic_class_is_reference_type (cfg, klass))
12712                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12713                                 else
12714                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12715                                 ip += 6;
12716                                 inline_costs += 1;
12717                                 break;
12718                         case CEE_CONSTRAINED_:
12719                                 CHECK_OPSIZE (6);
12720                                 token = read32 (ip + 2);
12721                                 constrained_class = mini_get_class (method, token, generic_context);
12722                                 CHECK_TYPELOAD (constrained_class);
12723                                 ip += 6;
12724                                 break;
12725                         case CEE_CPBLK:
12726                         case CEE_INITBLK: {
12727                                 MonoInst *iargs [3];
12728                                 CHECK_STACK (3);
12729                                 sp -= 3;
12730
12731                                 /* Skip optimized paths for volatile operations. */
12732                                 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)) {
12733                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12734                                 } 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)) {
12735                                         /* emit_memset only works when val == 0 */
12736                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12737                                 } else {
12738                                         MonoInst *call;
12739                                         iargs [0] = sp [0];
12740                                         iargs [1] = sp [1];
12741                                         iargs [2] = sp [2];
12742                                         if (ip [1] == CEE_CPBLK) {
12743                                                 /*
12744                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12745                                                  * and release barriers for cpblk. It is technically both a load and
12746                                                  * store operation, so it seems like that's the sensible thing to do.
12747                                                  *
12748                                                  * FIXME: We emit full barriers on both sides of the operation for
12749                                                  * simplicity. We should have a separate atomic memcpy method instead.
12750                                                  */
12751                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12752
12753                                                 if (ins_flag & MONO_INST_VOLATILE)
12754                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12755
12756                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12757                                                 call->flags |= ins_flag;
12758
12759                                                 if (ins_flag & MONO_INST_VOLATILE)
12760                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12761                                         } else {
12762                                                 MonoMethod *memset_method = get_memset_method ();
12763                                                 if (ins_flag & MONO_INST_VOLATILE) {
12764                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12765                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12766                                                 }
12767                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12768                                                 call->flags |= ins_flag;
12769                                         }
12770                                 }
12771                                 ip += 2;
12772                                 ins_flag = 0;
12773                                 inline_costs += 1;
12774                                 break;
12775                         }
12776                         case CEE_NO_:
12777                                 CHECK_OPSIZE (3);
12778                                 if (ip [2] & 0x1)
12779                                         ins_flag |= MONO_INST_NOTYPECHECK;
12780                                 if (ip [2] & 0x2)
12781                                         ins_flag |= MONO_INST_NORANGECHECK;
12782                                 /* we ignore the no-nullcheck for now since we
12783                                  * really do it explicitly only when doing callvirt->call
12784                                  */
12785                                 ip += 3;
12786                                 break;
12787                         case CEE_RETHROW: {
12788                                 MonoInst *load;
12789                                 int handler_offset = -1;
12790
12791                                 for (i = 0; i < header->num_clauses; ++i) {
12792                                         MonoExceptionClause *clause = &header->clauses [i];
12793                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12794                                                 handler_offset = clause->handler_offset;
12795                                                 break;
12796                                         }
12797                                 }
12798
12799                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12800
12801                                 if (handler_offset == -1)
12802                                         UNVERIFIED;
12803
12804                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12805                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12806                                 ins->sreg1 = load->dreg;
12807                                 MONO_ADD_INS (bblock, ins);
12808
12809                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12810                                 MONO_ADD_INS (bblock, ins);
12811
12812                                 sp = stack_start;
12813                                 link_bblock (cfg, bblock, end_bblock);
12814                                 start_new_bblock = 1;
12815                                 ip += 2;
12816                                 break;
12817                         }
12818                         case CEE_SIZEOF: {
12819                                 guint32 val;
12820                                 int ialign;
12821
12822                                 CHECK_STACK_OVF (1);
12823                                 CHECK_OPSIZE (6);
12824                                 token = read32 (ip + 2);
12825                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12826                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12827                                         CHECK_CFG_ERROR;
12828
12829                                         val = mono_type_size (type, &ialign);
12830                                 } else {
12831                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12832                                         CHECK_TYPELOAD (klass);
12833
12834                                         val = mono_type_size (&klass->byval_arg, &ialign);
12835
12836                                         if (mini_is_gsharedvt_klass (cfg, klass))
12837                                                 GSHAREDVT_FAILURE (*ip);
12838                                 }
12839                                 EMIT_NEW_ICONST (cfg, ins, val);
12840                                 *sp++= ins;
12841                                 ip += 6;
12842                                 break;
12843                         }
12844                         case CEE_REFANYTYPE: {
12845                                 MonoInst *src_var, *src;
12846
12847                                 GSHAREDVT_FAILURE (*ip);
12848
12849                                 CHECK_STACK (1);
12850                                 --sp;
12851
12852                                 // FIXME:
12853                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12854                                 if (!src_var)
12855                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12856                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12857                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12858                                 *sp++ = ins;
12859                                 ip += 2;
12860                                 break;
12861                         }
12862                         case CEE_READONLY_:
12863                                 readonly = TRUE;
12864                                 ip += 2;
12865                                 break;
12866
12867                         case CEE_UNUSED56:
12868                         case CEE_UNUSED57:
12869                         case CEE_UNUSED70:
12870                         case CEE_UNUSED:
12871                         case CEE_UNUSED99:
12872                                 UNVERIFIED;
12873                                 
12874                         default:
12875                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12876                                 UNVERIFIED;
12877                         }
12878                         break;
12879                 }
12880                 case CEE_UNUSED58:
12881                 case CEE_UNUSED1:
12882                         UNVERIFIED;
12883
12884                 default:
12885                         g_warning ("opcode 0x%02x not handled", *ip);
12886                         UNVERIFIED;
12887                 }
12888         }
12889         if (start_new_bblock != 1)
12890                 UNVERIFIED;
12891
12892         bblock->cil_length = ip - bblock->cil_code;
12893         if (bblock->next_bb) {
12894                 /* This could already be set because of inlining, #693905 */
12895                 MonoBasicBlock *bb = bblock;
12896
12897                 while (bb->next_bb)
12898                         bb = bb->next_bb;
12899                 bb->next_bb = end_bblock;
12900         } else {
12901                 bblock->next_bb = end_bblock;
12902         }
12903
12904         if (cfg->method == method && cfg->domainvar) {
12905                 MonoInst *store;
12906                 MonoInst *get_domain;
12907
12908                 cfg->cbb = init_localsbb;
12909
12910                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12911                         MONO_ADD_INS (cfg->cbb, get_domain);
12912                 } else {
12913                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12914                 }
12915                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12916                 MONO_ADD_INS (cfg->cbb, store);
12917         }
12918
12919 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12920         if (cfg->compile_aot)
12921                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12922                 mono_get_got_var (cfg);
12923 #endif
12924
12925         if (cfg->method == method && cfg->got_var)
12926                 mono_emit_load_got_addr (cfg);
12927
12928         if (init_localsbb) {
12929                 cfg->cbb = init_localsbb;
12930                 cfg->ip = NULL;
12931                 for (i = 0; i < header->num_locals; ++i) {
12932                         emit_init_local (cfg, i, header->locals [i], init_locals);
12933                 }
12934         }
12935
12936         if (cfg->init_ref_vars && cfg->method == method) {
12937                 /* Emit initialization for ref vars */
12938                 // FIXME: Avoid duplication initialization for IL locals.
12939                 for (i = 0; i < cfg->num_varinfo; ++i) {
12940                         MonoInst *ins = cfg->varinfo [i];
12941
12942                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12943                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12944                 }
12945         }
12946
12947         if (cfg->lmf_var && cfg->method == method) {
12948                 cfg->cbb = init_localsbb;
12949                 emit_push_lmf (cfg);
12950         }
12951
12952         cfg->cbb = init_localsbb;
12953         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12954
12955         if (seq_points) {
12956                 MonoBasicBlock *bb;
12957
12958                 /*
12959                  * Make seq points at backward branch targets interruptable.
12960                  */
12961                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12962                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12963                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12964         }
12965
12966         /* Add a sequence point for method entry/exit events */
12967         if (cfg->gen_seq_points_debug_data) {
12968                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12969                 MONO_ADD_INS (init_localsbb, ins);
12970                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12971                 MONO_ADD_INS (cfg->bb_exit, ins);
12972         }
12973
12974         /*
12975          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12976          * the code they refer to was dead (#11880).
12977          */
12978         if (sym_seq_points) {
12979                 for (i = 0; i < header->code_size; ++i) {
12980                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12981                                 MonoInst *ins;
12982
12983                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12984                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12985                         }
12986                 }
12987         }
12988
12989         cfg->ip = NULL;
12990
12991         if (cfg->method == method) {
12992                 MonoBasicBlock *bb;
12993                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12994                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12995                         if (cfg->spvars)
12996                                 mono_create_spvar_for_region (cfg, bb->region);
12997                         if (cfg->verbose_level > 2)
12998                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12999                 }
13000         }
13001
13002         if (inline_costs < 0) {
13003                 char *mname;
13004
13005                 /* Method is too large */
13006                 mname = mono_method_full_name (method, TRUE);
13007                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13008                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13009                 g_free (mname);
13010         }
13011
13012         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13013                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13014
13015         goto cleanup;
13016
13017 mono_error_exit:
13018         g_assert (!mono_error_ok (&cfg->error));
13019         goto cleanup;
13020  
13021  exception_exit:
13022         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13023         goto cleanup;
13024
13025  unverified:
13026         set_exception_type_from_invalid_il (cfg, method, ip);
13027         goto cleanup;
13028
13029  cleanup:
13030         g_slist_free (class_inits);
13031         mono_basic_block_free (original_bb);
13032         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13033         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13034         if (cfg->exception_type)
13035                 return -1;
13036         else
13037                 return inline_costs;
13038 }
13039
13040 static int
13041 store_membase_reg_to_store_membase_imm (int opcode)
13042 {
13043         switch (opcode) {
13044         case OP_STORE_MEMBASE_REG:
13045                 return OP_STORE_MEMBASE_IMM;
13046         case OP_STOREI1_MEMBASE_REG:
13047                 return OP_STOREI1_MEMBASE_IMM;
13048         case OP_STOREI2_MEMBASE_REG:
13049                 return OP_STOREI2_MEMBASE_IMM;
13050         case OP_STOREI4_MEMBASE_REG:
13051                 return OP_STOREI4_MEMBASE_IMM;
13052         case OP_STOREI8_MEMBASE_REG:
13053                 return OP_STOREI8_MEMBASE_IMM;
13054         default:
13055                 g_assert_not_reached ();
13056         }
13057
13058         return -1;
13059 }               
13060
13061 int
13062 mono_op_to_op_imm (int opcode)
13063 {
13064         switch (opcode) {
13065         case OP_IADD:
13066                 return OP_IADD_IMM;
13067         case OP_ISUB:
13068                 return OP_ISUB_IMM;
13069         case OP_IDIV:
13070                 return OP_IDIV_IMM;
13071         case OP_IDIV_UN:
13072                 return OP_IDIV_UN_IMM;
13073         case OP_IREM:
13074                 return OP_IREM_IMM;
13075         case OP_IREM_UN:
13076                 return OP_IREM_UN_IMM;
13077         case OP_IMUL:
13078                 return OP_IMUL_IMM;
13079         case OP_IAND:
13080                 return OP_IAND_IMM;
13081         case OP_IOR:
13082                 return OP_IOR_IMM;
13083         case OP_IXOR:
13084                 return OP_IXOR_IMM;
13085         case OP_ISHL:
13086                 return OP_ISHL_IMM;
13087         case OP_ISHR:
13088                 return OP_ISHR_IMM;
13089         case OP_ISHR_UN:
13090                 return OP_ISHR_UN_IMM;
13091
13092         case OP_LADD:
13093                 return OP_LADD_IMM;
13094         case OP_LSUB:
13095                 return OP_LSUB_IMM;
13096         case OP_LAND:
13097                 return OP_LAND_IMM;
13098         case OP_LOR:
13099                 return OP_LOR_IMM;
13100         case OP_LXOR:
13101                 return OP_LXOR_IMM;
13102         case OP_LSHL:
13103                 return OP_LSHL_IMM;
13104         case OP_LSHR:
13105                 return OP_LSHR_IMM;
13106         case OP_LSHR_UN:
13107                 return OP_LSHR_UN_IMM;
13108 #if SIZEOF_REGISTER == 8
13109         case OP_LREM:
13110                 return OP_LREM_IMM;
13111 #endif
13112
13113         case OP_COMPARE:
13114                 return OP_COMPARE_IMM;
13115         case OP_ICOMPARE:
13116                 return OP_ICOMPARE_IMM;
13117         case OP_LCOMPARE:
13118                 return OP_LCOMPARE_IMM;
13119
13120         case OP_STORE_MEMBASE_REG:
13121                 return OP_STORE_MEMBASE_IMM;
13122         case OP_STOREI1_MEMBASE_REG:
13123                 return OP_STOREI1_MEMBASE_IMM;
13124         case OP_STOREI2_MEMBASE_REG:
13125                 return OP_STOREI2_MEMBASE_IMM;
13126         case OP_STOREI4_MEMBASE_REG:
13127                 return OP_STOREI4_MEMBASE_IMM;
13128
13129 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13130         case OP_X86_PUSH:
13131                 return OP_X86_PUSH_IMM;
13132         case OP_X86_COMPARE_MEMBASE_REG:
13133                 return OP_X86_COMPARE_MEMBASE_IMM;
13134 #endif
13135 #if defined(TARGET_AMD64)
13136         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13137                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13138 #endif
13139         case OP_VOIDCALL_REG:
13140                 return OP_VOIDCALL;
13141         case OP_CALL_REG:
13142                 return OP_CALL;
13143         case OP_LCALL_REG:
13144                 return OP_LCALL;
13145         case OP_FCALL_REG:
13146                 return OP_FCALL;
13147         case OP_LOCALLOC:
13148                 return OP_LOCALLOC_IMM;
13149         }
13150
13151         return -1;
13152 }
13153
13154 static int
13155 ldind_to_load_membase (int opcode)
13156 {
13157         switch (opcode) {
13158         case CEE_LDIND_I1:
13159                 return OP_LOADI1_MEMBASE;
13160         case CEE_LDIND_U1:
13161                 return OP_LOADU1_MEMBASE;
13162         case CEE_LDIND_I2:
13163                 return OP_LOADI2_MEMBASE;
13164         case CEE_LDIND_U2:
13165                 return OP_LOADU2_MEMBASE;
13166         case CEE_LDIND_I4:
13167                 return OP_LOADI4_MEMBASE;
13168         case CEE_LDIND_U4:
13169                 return OP_LOADU4_MEMBASE;
13170         case CEE_LDIND_I:
13171                 return OP_LOAD_MEMBASE;
13172         case CEE_LDIND_REF:
13173                 return OP_LOAD_MEMBASE;
13174         case CEE_LDIND_I8:
13175                 return OP_LOADI8_MEMBASE;
13176         case CEE_LDIND_R4:
13177                 return OP_LOADR4_MEMBASE;
13178         case CEE_LDIND_R8:
13179                 return OP_LOADR8_MEMBASE;
13180         default:
13181                 g_assert_not_reached ();
13182         }
13183
13184         return -1;
13185 }
13186
13187 static int
13188 stind_to_store_membase (int opcode)
13189 {
13190         switch (opcode) {
13191         case CEE_STIND_I1:
13192                 return OP_STOREI1_MEMBASE_REG;
13193         case CEE_STIND_I2:
13194                 return OP_STOREI2_MEMBASE_REG;
13195         case CEE_STIND_I4:
13196                 return OP_STOREI4_MEMBASE_REG;
13197         case CEE_STIND_I:
13198         case CEE_STIND_REF:
13199                 return OP_STORE_MEMBASE_REG;
13200         case CEE_STIND_I8:
13201                 return OP_STOREI8_MEMBASE_REG;
13202         case CEE_STIND_R4:
13203                 return OP_STORER4_MEMBASE_REG;
13204         case CEE_STIND_R8:
13205                 return OP_STORER8_MEMBASE_REG;
13206         default:
13207                 g_assert_not_reached ();
13208         }
13209
13210         return -1;
13211 }
13212
13213 int
13214 mono_load_membase_to_load_mem (int opcode)
13215 {
13216         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13217 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13218         switch (opcode) {
13219         case OP_LOAD_MEMBASE:
13220                 return OP_LOAD_MEM;
13221         case OP_LOADU1_MEMBASE:
13222                 return OP_LOADU1_MEM;
13223         case OP_LOADU2_MEMBASE:
13224                 return OP_LOADU2_MEM;
13225         case OP_LOADI4_MEMBASE:
13226                 return OP_LOADI4_MEM;
13227         case OP_LOADU4_MEMBASE:
13228                 return OP_LOADU4_MEM;
13229 #if SIZEOF_REGISTER == 8
13230         case OP_LOADI8_MEMBASE:
13231                 return OP_LOADI8_MEM;
13232 #endif
13233         }
13234 #endif
13235
13236         return -1;
13237 }
13238
13239 static inline int
13240 op_to_op_dest_membase (int store_opcode, int opcode)
13241 {
13242 #if defined(TARGET_X86)
13243         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13244                 return -1;
13245
13246         switch (opcode) {
13247         case OP_IADD:
13248                 return OP_X86_ADD_MEMBASE_REG;
13249         case OP_ISUB:
13250                 return OP_X86_SUB_MEMBASE_REG;
13251         case OP_IAND:
13252                 return OP_X86_AND_MEMBASE_REG;
13253         case OP_IOR:
13254                 return OP_X86_OR_MEMBASE_REG;
13255         case OP_IXOR:
13256                 return OP_X86_XOR_MEMBASE_REG;
13257         case OP_ADD_IMM:
13258         case OP_IADD_IMM:
13259                 return OP_X86_ADD_MEMBASE_IMM;
13260         case OP_SUB_IMM:
13261         case OP_ISUB_IMM:
13262                 return OP_X86_SUB_MEMBASE_IMM;
13263         case OP_AND_IMM:
13264         case OP_IAND_IMM:
13265                 return OP_X86_AND_MEMBASE_IMM;
13266         case OP_OR_IMM:
13267         case OP_IOR_IMM:
13268                 return OP_X86_OR_MEMBASE_IMM;
13269         case OP_XOR_IMM:
13270         case OP_IXOR_IMM:
13271                 return OP_X86_XOR_MEMBASE_IMM;
13272         case OP_MOVE:
13273                 return OP_NOP;
13274         }
13275 #endif
13276
13277 #if defined(TARGET_AMD64)
13278         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13279                 return -1;
13280
13281         switch (opcode) {
13282         case OP_IADD:
13283                 return OP_X86_ADD_MEMBASE_REG;
13284         case OP_ISUB:
13285                 return OP_X86_SUB_MEMBASE_REG;
13286         case OP_IAND:
13287                 return OP_X86_AND_MEMBASE_REG;
13288         case OP_IOR:
13289                 return OP_X86_OR_MEMBASE_REG;
13290         case OP_IXOR:
13291                 return OP_X86_XOR_MEMBASE_REG;
13292         case OP_IADD_IMM:
13293                 return OP_X86_ADD_MEMBASE_IMM;
13294         case OP_ISUB_IMM:
13295                 return OP_X86_SUB_MEMBASE_IMM;
13296         case OP_IAND_IMM:
13297                 return OP_X86_AND_MEMBASE_IMM;
13298         case OP_IOR_IMM:
13299                 return OP_X86_OR_MEMBASE_IMM;
13300         case OP_IXOR_IMM:
13301                 return OP_X86_XOR_MEMBASE_IMM;
13302         case OP_LADD:
13303                 return OP_AMD64_ADD_MEMBASE_REG;
13304         case OP_LSUB:
13305                 return OP_AMD64_SUB_MEMBASE_REG;
13306         case OP_LAND:
13307                 return OP_AMD64_AND_MEMBASE_REG;
13308         case OP_LOR:
13309                 return OP_AMD64_OR_MEMBASE_REG;
13310         case OP_LXOR:
13311                 return OP_AMD64_XOR_MEMBASE_REG;
13312         case OP_ADD_IMM:
13313         case OP_LADD_IMM:
13314                 return OP_AMD64_ADD_MEMBASE_IMM;
13315         case OP_SUB_IMM:
13316         case OP_LSUB_IMM:
13317                 return OP_AMD64_SUB_MEMBASE_IMM;
13318         case OP_AND_IMM:
13319         case OP_LAND_IMM:
13320                 return OP_AMD64_AND_MEMBASE_IMM;
13321         case OP_OR_IMM:
13322         case OP_LOR_IMM:
13323                 return OP_AMD64_OR_MEMBASE_IMM;
13324         case OP_XOR_IMM:
13325         case OP_LXOR_IMM:
13326                 return OP_AMD64_XOR_MEMBASE_IMM;
13327         case OP_MOVE:
13328                 return OP_NOP;
13329         }
13330 #endif
13331
13332         return -1;
13333 }
13334
13335 static inline int
13336 op_to_op_store_membase (int store_opcode, int opcode)
13337 {
13338 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13339         switch (opcode) {
13340         case OP_ICEQ:
13341                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13342                         return OP_X86_SETEQ_MEMBASE;
13343         case OP_CNE:
13344                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13345                         return OP_X86_SETNE_MEMBASE;
13346         }
13347 #endif
13348
13349         return -1;
13350 }
13351
13352 static inline int
13353 op_to_op_src1_membase (int load_opcode, int opcode)
13354 {
13355 #ifdef TARGET_X86
13356         /* FIXME: This has sign extension issues */
13357         /*
13358         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13359                 return OP_X86_COMPARE_MEMBASE8_IMM;
13360         */
13361
13362         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13363                 return -1;
13364
13365         switch (opcode) {
13366         case OP_X86_PUSH:
13367                 return OP_X86_PUSH_MEMBASE;
13368         case OP_COMPARE_IMM:
13369         case OP_ICOMPARE_IMM:
13370                 return OP_X86_COMPARE_MEMBASE_IMM;
13371         case OP_COMPARE:
13372         case OP_ICOMPARE:
13373                 return OP_X86_COMPARE_MEMBASE_REG;
13374         }
13375 #endif
13376
13377 #ifdef TARGET_AMD64
13378         /* FIXME: This has sign extension issues */
13379         /*
13380         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13381                 return OP_X86_COMPARE_MEMBASE8_IMM;
13382         */
13383
13384         switch (opcode) {
13385         case OP_X86_PUSH:
13386 #ifdef __mono_ilp32__
13387                 if (load_opcode == OP_LOADI8_MEMBASE)
13388 #else
13389                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13390 #endif
13391                         return OP_X86_PUSH_MEMBASE;
13392                 break;
13393                 /* FIXME: This only works for 32 bit immediates
13394         case OP_COMPARE_IMM:
13395         case OP_LCOMPARE_IMM:
13396                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13397                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13398                 */
13399         case OP_ICOMPARE_IMM:
13400                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13401                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13402                 break;
13403         case OP_COMPARE:
13404         case OP_LCOMPARE:
13405 #ifdef __mono_ilp32__
13406                 if (load_opcode == OP_LOAD_MEMBASE)
13407                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13408                 if (load_opcode == OP_LOADI8_MEMBASE)
13409 #else
13410                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13411 #endif
13412                         return OP_AMD64_COMPARE_MEMBASE_REG;
13413                 break;
13414         case OP_ICOMPARE:
13415                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13416                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13417                 break;
13418         }
13419 #endif
13420
13421         return -1;
13422 }
13423
13424 static inline int
13425 op_to_op_src2_membase (int load_opcode, int opcode)
13426 {
13427 #ifdef TARGET_X86
13428         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13429                 return -1;
13430         
13431         switch (opcode) {
13432         case OP_COMPARE:
13433         case OP_ICOMPARE:
13434                 return OP_X86_COMPARE_REG_MEMBASE;
13435         case OP_IADD:
13436                 return OP_X86_ADD_REG_MEMBASE;
13437         case OP_ISUB:
13438                 return OP_X86_SUB_REG_MEMBASE;
13439         case OP_IAND:
13440                 return OP_X86_AND_REG_MEMBASE;
13441         case OP_IOR:
13442                 return OP_X86_OR_REG_MEMBASE;
13443         case OP_IXOR:
13444                 return OP_X86_XOR_REG_MEMBASE;
13445         }
13446 #endif
13447
13448 #ifdef TARGET_AMD64
13449 #ifdef __mono_ilp32__
13450         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13451 #else
13452         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13453 #endif
13454                 switch (opcode) {
13455                 case OP_ICOMPARE:
13456                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13457                 case OP_IADD:
13458                         return OP_X86_ADD_REG_MEMBASE;
13459                 case OP_ISUB:
13460                         return OP_X86_SUB_REG_MEMBASE;
13461                 case OP_IAND:
13462                         return OP_X86_AND_REG_MEMBASE;
13463                 case OP_IOR:
13464                         return OP_X86_OR_REG_MEMBASE;
13465                 case OP_IXOR:
13466                         return OP_X86_XOR_REG_MEMBASE;
13467                 }
13468 #ifdef __mono_ilp32__
13469         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13470 #else
13471         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13472 #endif
13473                 switch (opcode) {
13474                 case OP_COMPARE:
13475                 case OP_LCOMPARE:
13476                         return OP_AMD64_COMPARE_REG_MEMBASE;
13477                 case OP_LADD:
13478                         return OP_AMD64_ADD_REG_MEMBASE;
13479                 case OP_LSUB:
13480                         return OP_AMD64_SUB_REG_MEMBASE;
13481                 case OP_LAND:
13482                         return OP_AMD64_AND_REG_MEMBASE;
13483                 case OP_LOR:
13484                         return OP_AMD64_OR_REG_MEMBASE;
13485                 case OP_LXOR:
13486                         return OP_AMD64_XOR_REG_MEMBASE;
13487                 }
13488         }
13489 #endif
13490
13491         return -1;
13492 }
13493
13494 int
13495 mono_op_to_op_imm_noemul (int opcode)
13496 {
13497         switch (opcode) {
13498 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13499         case OP_LSHR:
13500         case OP_LSHL:
13501         case OP_LSHR_UN:
13502                 return -1;
13503 #endif
13504 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13505         case OP_IDIV:
13506         case OP_IDIV_UN:
13507         case OP_IREM:
13508         case OP_IREM_UN:
13509                 return -1;
13510 #endif
13511 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13512         case OP_IMUL:
13513                 return -1;
13514 #endif
13515         default:
13516                 return mono_op_to_op_imm (opcode);
13517         }
13518 }
13519
13520 /**
13521  * mono_handle_global_vregs:
13522  *
13523  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13524  * for them.
13525  */
13526 void
13527 mono_handle_global_vregs (MonoCompile *cfg)
13528 {
13529         gint32 *vreg_to_bb;
13530         MonoBasicBlock *bb;
13531         int i, pos;
13532
13533         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13534
13535 #ifdef MONO_ARCH_SIMD_INTRINSICS
13536         if (cfg->uses_simd_intrinsics)
13537                 mono_simd_simplify_indirection (cfg);
13538 #endif
13539
13540         /* Find local vregs used in more than one bb */
13541         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13542                 MonoInst *ins = bb->code;       
13543                 int block_num = bb->block_num;
13544
13545                 if (cfg->verbose_level > 2)
13546                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13547
13548                 cfg->cbb = bb;
13549                 for (; ins; ins = ins->next) {
13550                         const char *spec = INS_INFO (ins->opcode);
13551                         int regtype = 0, regindex;
13552                         gint32 prev_bb;
13553
13554                         if (G_UNLIKELY (cfg->verbose_level > 2))
13555                                 mono_print_ins (ins);
13556
13557                         g_assert (ins->opcode >= MONO_CEE_LAST);
13558
13559                         for (regindex = 0; regindex < 4; regindex ++) {
13560                                 int vreg = 0;
13561
13562                                 if (regindex == 0) {
13563                                         regtype = spec [MONO_INST_DEST];
13564                                         if (regtype == ' ')
13565                                                 continue;
13566                                         vreg = ins->dreg;
13567                                 } else if (regindex == 1) {
13568                                         regtype = spec [MONO_INST_SRC1];
13569                                         if (regtype == ' ')
13570                                                 continue;
13571                                         vreg = ins->sreg1;
13572                                 } else if (regindex == 2) {
13573                                         regtype = spec [MONO_INST_SRC2];
13574                                         if (regtype == ' ')
13575                                                 continue;
13576                                         vreg = ins->sreg2;
13577                                 } else if (regindex == 3) {
13578                                         regtype = spec [MONO_INST_SRC3];
13579                                         if (regtype == ' ')
13580                                                 continue;
13581                                         vreg = ins->sreg3;
13582                                 }
13583
13584 #if SIZEOF_REGISTER == 4
13585                                 /* In the LLVM case, the long opcodes are not decomposed */
13586                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13587                                         /*
13588                                          * Since some instructions reference the original long vreg,
13589                                          * and some reference the two component vregs, it is quite hard
13590                                          * to determine when it needs to be global. So be conservative.
13591                                          */
13592                                         if (!get_vreg_to_inst (cfg, vreg)) {
13593                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13594
13595                                                 if (cfg->verbose_level > 2)
13596                                                         printf ("LONG VREG R%d made global.\n", vreg);
13597                                         }
13598
13599                                         /*
13600                                          * Make the component vregs volatile since the optimizations can
13601                                          * get confused otherwise.
13602                                          */
13603                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13604                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13605                                 }
13606 #endif
13607
13608                                 g_assert (vreg != -1);
13609
13610                                 prev_bb = vreg_to_bb [vreg];
13611                                 if (prev_bb == 0) {
13612                                         /* 0 is a valid block num */
13613                                         vreg_to_bb [vreg] = block_num + 1;
13614                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13615                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13616                                                 continue;
13617
13618                                         if (!get_vreg_to_inst (cfg, vreg)) {
13619                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13620                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13621
13622                                                 switch (regtype) {
13623                                                 case 'i':
13624                                                         if (vreg_is_ref (cfg, vreg))
13625                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13626                                                         else
13627                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13628                                                         break;
13629                                                 case 'l':
13630                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13631                                                         break;
13632                                                 case 'f':
13633                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13634                                                         break;
13635                                                 case 'v':
13636                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13637                                                         break;
13638                                                 default:
13639                                                         g_assert_not_reached ();
13640                                                 }
13641                                         }
13642
13643                                         /* Flag as having been used in more than one bb */
13644                                         vreg_to_bb [vreg] = -1;
13645                                 }
13646                         }
13647                 }
13648         }
13649
13650         /* If a variable is used in only one bblock, convert it into a local vreg */
13651         for (i = 0; i < cfg->num_varinfo; i++) {
13652                 MonoInst *var = cfg->varinfo [i];
13653                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13654
13655                 switch (var->type) {
13656                 case STACK_I4:
13657                 case STACK_OBJ:
13658                 case STACK_PTR:
13659                 case STACK_MP:
13660                 case STACK_VTYPE:
13661 #if SIZEOF_REGISTER == 8
13662                 case STACK_I8:
13663 #endif
13664 #if !defined(TARGET_X86)
13665                 /* Enabling this screws up the fp stack on x86 */
13666                 case STACK_R8:
13667 #endif
13668                         if (mono_arch_is_soft_float ())
13669                                 break;
13670
13671                         /* Arguments are implicitly global */
13672                         /* Putting R4 vars into registers doesn't work currently */
13673                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13674                         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) {
13675                                 /* 
13676                                  * Make that the variable's liveness interval doesn't contain a call, since
13677                                  * that would cause the lvreg to be spilled, making the whole optimization
13678                                  * useless.
13679                                  */
13680                                 /* This is too slow for JIT compilation */
13681 #if 0
13682                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13683                                         MonoInst *ins;
13684                                         int def_index, call_index, ins_index;
13685                                         gboolean spilled = FALSE;
13686
13687                                         def_index = -1;
13688                                         call_index = -1;
13689                                         ins_index = 0;
13690                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13691                                                 const char *spec = INS_INFO (ins->opcode);
13692
13693                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13694                                                         def_index = ins_index;
13695
13696                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13697                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13698                                                         if (call_index > def_index) {
13699                                                                 spilled = TRUE;
13700                                                                 break;
13701                                                         }
13702                                                 }
13703
13704                                                 if (MONO_IS_CALL (ins))
13705                                                         call_index = ins_index;
13706
13707                                                 ins_index ++;
13708                                         }
13709
13710                                         if (spilled)
13711                                                 break;
13712                                 }
13713 #endif
13714
13715                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13716                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13717                                 var->flags |= MONO_INST_IS_DEAD;
13718                                 cfg->vreg_to_inst [var->dreg] = NULL;
13719                         }
13720                         break;
13721                 }
13722         }
13723
13724         /* 
13725          * Compress the varinfo and vars tables so the liveness computation is faster and
13726          * takes up less space.
13727          */
13728         pos = 0;
13729         for (i = 0; i < cfg->num_varinfo; ++i) {
13730                 MonoInst *var = cfg->varinfo [i];
13731                 if (pos < i && cfg->locals_start == i)
13732                         cfg->locals_start = pos;
13733                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13734                         if (pos < i) {
13735                                 cfg->varinfo [pos] = cfg->varinfo [i];
13736                                 cfg->varinfo [pos]->inst_c0 = pos;
13737                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13738                                 cfg->vars [pos].idx = pos;
13739 #if SIZEOF_REGISTER == 4
13740                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13741                                         /* Modify the two component vars too */
13742                                         MonoInst *var1;
13743
13744                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13745                                         var1->inst_c0 = pos;
13746                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13747                                         var1->inst_c0 = pos;
13748                                 }
13749 #endif
13750                         }
13751                         pos ++;
13752                 }
13753         }
13754         cfg->num_varinfo = pos;
13755         if (cfg->locals_start > cfg->num_varinfo)
13756                 cfg->locals_start = cfg->num_varinfo;
13757 }
13758
13759 /**
13760  * mono_spill_global_vars:
13761  *
13762  *   Generate spill code for variables which are not allocated to registers, 
13763  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13764  * code is generated which could be optimized by the local optimization passes.
13765  */
13766 void
13767 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13768 {
13769         MonoBasicBlock *bb;
13770         char spec2 [16];
13771         int orig_next_vreg;
13772         guint32 *vreg_to_lvreg;
13773         guint32 *lvregs;
13774         guint32 i, lvregs_len;
13775         gboolean dest_has_lvreg = FALSE;
13776         guint32 stacktypes [128];
13777         MonoInst **live_range_start, **live_range_end;
13778         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13779         int *gsharedvt_vreg_to_idx = NULL;
13780
13781         *need_local_opts = FALSE;
13782
13783         memset (spec2, 0, sizeof (spec2));
13784
13785         /* FIXME: Move this function to mini.c */
13786         stacktypes ['i'] = STACK_PTR;
13787         stacktypes ['l'] = STACK_I8;
13788         stacktypes ['f'] = STACK_R8;
13789 #ifdef MONO_ARCH_SIMD_INTRINSICS
13790         stacktypes ['x'] = STACK_VTYPE;
13791 #endif
13792
13793 #if SIZEOF_REGISTER == 4
13794         /* Create MonoInsts for longs */
13795         for (i = 0; i < cfg->num_varinfo; i++) {
13796                 MonoInst *ins = cfg->varinfo [i];
13797
13798                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13799                         switch (ins->type) {
13800                         case STACK_R8:
13801                         case STACK_I8: {
13802                                 MonoInst *tree;
13803
13804                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13805                                         break;
13806
13807                                 g_assert (ins->opcode == OP_REGOFFSET);
13808
13809                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13810                                 g_assert (tree);
13811                                 tree->opcode = OP_REGOFFSET;
13812                                 tree->inst_basereg = ins->inst_basereg;
13813                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13814
13815                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13816                                 g_assert (tree);
13817                                 tree->opcode = OP_REGOFFSET;
13818                                 tree->inst_basereg = ins->inst_basereg;
13819                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13820                                 break;
13821                         }
13822                         default:
13823                                 break;
13824                         }
13825                 }
13826         }
13827 #endif
13828
13829         if (cfg->compute_gc_maps) {
13830                 /* registers need liveness info even for !non refs */
13831                 for (i = 0; i < cfg->num_varinfo; i++) {
13832                         MonoInst *ins = cfg->varinfo [i];
13833
13834                         if (ins->opcode == OP_REGVAR)
13835                                 ins->flags |= MONO_INST_GC_TRACK;
13836                 }
13837         }
13838
13839         if (cfg->gsharedvt) {
13840                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13841
13842                 for (i = 0; i < cfg->num_varinfo; ++i) {
13843                         MonoInst *ins = cfg->varinfo [i];
13844                         int idx;
13845
13846                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13847                                 if (i >= cfg->locals_start) {
13848                                         /* Local */
13849                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13850                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13851                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13852                                         ins->inst_imm = idx;
13853                                 } else {
13854                                         /* Arg */
13855                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13856                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13857                                 }
13858                         }
13859                 }
13860         }
13861                 
13862         /* FIXME: widening and truncation */
13863
13864         /*
13865          * As an optimization, when a variable allocated to the stack is first loaded into 
13866          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13867          * the variable again.
13868          */
13869         orig_next_vreg = cfg->next_vreg;
13870         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13871         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13872         lvregs_len = 0;
13873
13874         /* 
13875          * These arrays contain the first and last instructions accessing a given
13876          * variable.
13877          * Since we emit bblocks in the same order we process them here, and we
13878          * don't split live ranges, these will precisely describe the live range of
13879          * the variable, i.e. the instruction range where a valid value can be found
13880          * in the variables location.
13881          * The live range is computed using the liveness info computed by the liveness pass.
13882          * We can't use vmv->range, since that is an abstract live range, and we need
13883          * one which is instruction precise.
13884          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13885          */
13886         /* FIXME: Only do this if debugging info is requested */
13887         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13888         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13889         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13890         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13891         
13892         /* Add spill loads/stores */
13893         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13894                 MonoInst *ins;
13895
13896                 if (cfg->verbose_level > 2)
13897                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13898
13899                 /* Clear vreg_to_lvreg array */
13900                 for (i = 0; i < lvregs_len; i++)
13901                         vreg_to_lvreg [lvregs [i]] = 0;
13902                 lvregs_len = 0;
13903
13904                 cfg->cbb = bb;
13905                 MONO_BB_FOR_EACH_INS (bb, ins) {
13906                         const char *spec = INS_INFO (ins->opcode);
13907                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13908                         gboolean store, no_lvreg;
13909                         int sregs [MONO_MAX_SRC_REGS];
13910
13911                         if (G_UNLIKELY (cfg->verbose_level > 2))
13912                                 mono_print_ins (ins);
13913
13914                         if (ins->opcode == OP_NOP)
13915                                 continue;
13916
13917                         /* 
13918                          * We handle LDADDR here as well, since it can only be decomposed
13919                          * when variable addresses are known.
13920                          */
13921                         if (ins->opcode == OP_LDADDR) {
13922                                 MonoInst *var = ins->inst_p0;
13923
13924                                 if (var->opcode == OP_VTARG_ADDR) {
13925                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13926                                         MonoInst *vtaddr = var->inst_left;
13927                                         if (vtaddr->opcode == OP_REGVAR) {
13928                                                 ins->opcode = OP_MOVE;
13929                                                 ins->sreg1 = vtaddr->dreg;
13930                                         }
13931                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13932                                                 ins->opcode = OP_LOAD_MEMBASE;
13933                                                 ins->inst_basereg = vtaddr->inst_basereg;
13934                                                 ins->inst_offset = vtaddr->inst_offset;
13935                                         } else
13936                                                 NOT_IMPLEMENTED;
13937                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13938                                         /* gsharedvt arg passed by ref */
13939                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13940
13941                                         ins->opcode = OP_LOAD_MEMBASE;
13942                                         ins->inst_basereg = var->inst_basereg;
13943                                         ins->inst_offset = var->inst_offset;
13944                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13945                                         MonoInst *load, *load2, *load3;
13946                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13947                                         int reg1, reg2, reg3;
13948                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13949                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13950
13951                                         /*
13952                                          * gsharedvt local.
13953                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13954                                          */
13955
13956                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13957
13958                                         g_assert (info_var);
13959                                         g_assert (locals_var);
13960
13961                                         /* Mark the instruction used to compute the locals var as used */
13962                                         cfg->gsharedvt_locals_var_ins = NULL;
13963
13964                                         /* Load the offset */
13965                                         if (info_var->opcode == OP_REGOFFSET) {
13966                                                 reg1 = alloc_ireg (cfg);
13967                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13968                                         } else if (info_var->opcode == OP_REGVAR) {
13969                                                 load = NULL;
13970                                                 reg1 = info_var->dreg;
13971                                         } else {
13972                                                 g_assert_not_reached ();
13973                                         }
13974                                         reg2 = alloc_ireg (cfg);
13975                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13976                                         /* Load the locals area address */
13977                                         reg3 = alloc_ireg (cfg);
13978                                         if (locals_var->opcode == OP_REGOFFSET) {
13979                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13980                                         } else if (locals_var->opcode == OP_REGVAR) {
13981                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13982                                         } else {
13983                                                 g_assert_not_reached ();
13984                                         }
13985                                         /* Compute the address */
13986                                         ins->opcode = OP_PADD;
13987                                         ins->sreg1 = reg3;
13988                                         ins->sreg2 = reg2;
13989
13990                                         mono_bblock_insert_before_ins (bb, ins, load3);
13991                                         mono_bblock_insert_before_ins (bb, load3, load2);
13992                                         if (load)
13993                                                 mono_bblock_insert_before_ins (bb, load2, load);
13994                                 } else {
13995                                         g_assert (var->opcode == OP_REGOFFSET);
13996
13997                                         ins->opcode = OP_ADD_IMM;
13998                                         ins->sreg1 = var->inst_basereg;
13999                                         ins->inst_imm = var->inst_offset;
14000                                 }
14001
14002                                 *need_local_opts = TRUE;
14003                                 spec = INS_INFO (ins->opcode);
14004                         }
14005
14006                         if (ins->opcode < MONO_CEE_LAST) {
14007                                 mono_print_ins (ins);
14008                                 g_assert_not_reached ();
14009                         }
14010
14011                         /*
14012                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14013                          * src register.
14014                          * FIXME:
14015                          */
14016                         if (MONO_IS_STORE_MEMBASE (ins)) {
14017                                 tmp_reg = ins->dreg;
14018                                 ins->dreg = ins->sreg2;
14019                                 ins->sreg2 = tmp_reg;
14020                                 store = TRUE;
14021
14022                                 spec2 [MONO_INST_DEST] = ' ';
14023                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14024                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14025                                 spec2 [MONO_INST_SRC3] = ' ';
14026                                 spec = spec2;
14027                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14028                                 g_assert_not_reached ();
14029                         else
14030                                 store = FALSE;
14031                         no_lvreg = FALSE;
14032
14033                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14034                                 printf ("\t %.3s %d", spec, ins->dreg);
14035                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14036                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14037                                         printf (" %d", sregs [srcindex]);
14038                                 printf ("\n");
14039                         }
14040
14041                         /***************/
14042                         /*    DREG     */
14043                         /***************/
14044                         regtype = spec [MONO_INST_DEST];
14045                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14046                         prev_dreg = -1;
14047
14048                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14049                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14050                                 MonoInst *store_ins;
14051                                 int store_opcode;
14052                                 MonoInst *def_ins = ins;
14053                                 int dreg = ins->dreg; /* The original vreg */
14054
14055                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14056
14057                                 if (var->opcode == OP_REGVAR) {
14058                                         ins->dreg = var->dreg;
14059                                 } 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)) {
14060                                         /* 
14061                                          * Instead of emitting a load+store, use a _membase opcode.
14062                                          */
14063                                         g_assert (var->opcode == OP_REGOFFSET);
14064                                         if (ins->opcode == OP_MOVE) {
14065                                                 NULLIFY_INS (ins);
14066                                                 def_ins = NULL;
14067                                         } else {
14068                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14069                                                 ins->inst_basereg = var->inst_basereg;
14070                                                 ins->inst_offset = var->inst_offset;
14071                                                 ins->dreg = -1;
14072                                         }
14073                                         spec = INS_INFO (ins->opcode);
14074                                 } else {
14075                                         guint32 lvreg;
14076
14077                                         g_assert (var->opcode == OP_REGOFFSET);
14078
14079                                         prev_dreg = ins->dreg;
14080
14081                                         /* Invalidate any previous lvreg for this vreg */
14082                                         vreg_to_lvreg [ins->dreg] = 0;
14083
14084                                         lvreg = 0;
14085
14086                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14087                                                 regtype = 'l';
14088                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14089                                         }
14090
14091                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14092
14093 #if SIZEOF_REGISTER != 8
14094                                         if (regtype == 'l') {
14095                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14096                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14097                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14098                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14099                                                 def_ins = store_ins;
14100                                         }
14101                                         else
14102 #endif
14103                                         {
14104                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14105
14106                                                 /* Try to fuse the store into the instruction itself */
14107                                                 /* FIXME: Add more instructions */
14108                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14109                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14110                                                         ins->inst_imm = ins->inst_c0;
14111                                                         ins->inst_destbasereg = var->inst_basereg;
14112                                                         ins->inst_offset = var->inst_offset;
14113                                                         spec = INS_INFO (ins->opcode);
14114                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14115                                                         ins->opcode = store_opcode;
14116                                                         ins->inst_destbasereg = var->inst_basereg;
14117                                                         ins->inst_offset = var->inst_offset;
14118
14119                                                         no_lvreg = TRUE;
14120
14121                                                         tmp_reg = ins->dreg;
14122                                                         ins->dreg = ins->sreg2;
14123                                                         ins->sreg2 = tmp_reg;
14124                                                         store = TRUE;
14125
14126                                                         spec2 [MONO_INST_DEST] = ' ';
14127                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14128                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14129                                                         spec2 [MONO_INST_SRC3] = ' ';
14130                                                         spec = spec2;
14131                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14132                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14133                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14134                                                         ins->dreg = -1;
14135                                                         ins->inst_basereg = var->inst_basereg;
14136                                                         ins->inst_offset = var->inst_offset;
14137                                                         spec = INS_INFO (ins->opcode);
14138                                                 } else {
14139                                                         /* printf ("INS: "); mono_print_ins (ins); */
14140                                                         /* Create a store instruction */
14141                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14142
14143                                                         /* Insert it after the instruction */
14144                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14145
14146                                                         def_ins = store_ins;
14147
14148                                                         /* 
14149                                                          * We can't assign ins->dreg to var->dreg here, since the
14150                                                          * sregs could use it. So set a flag, and do it after
14151                                                          * the sregs.
14152                                                          */
14153                                                         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)))
14154                                                                 dest_has_lvreg = TRUE;
14155                                                 }
14156                                         }
14157                                 }
14158
14159                                 if (def_ins && !live_range_start [dreg]) {
14160                                         live_range_start [dreg] = def_ins;
14161                                         live_range_start_bb [dreg] = bb;
14162                                 }
14163
14164                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14165                                         MonoInst *tmp;
14166
14167                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14168                                         tmp->inst_c1 = dreg;
14169                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14170                                 }
14171                         }
14172
14173                         /************/
14174                         /*  SREGS   */
14175                         /************/
14176                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14177                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14178                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14179                                 sreg = sregs [srcindex];
14180
14181                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14182                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14183                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14184                                         MonoInst *use_ins = ins;
14185                                         MonoInst *load_ins;
14186                                         guint32 load_opcode;
14187
14188                                         if (var->opcode == OP_REGVAR) {
14189                                                 sregs [srcindex] = var->dreg;
14190                                                 //mono_inst_set_src_registers (ins, sregs);
14191                                                 live_range_end [sreg] = use_ins;
14192                                                 live_range_end_bb [sreg] = bb;
14193
14194                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14195                                                         MonoInst *tmp;
14196
14197                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14198                                                         /* var->dreg is a hreg */
14199                                                         tmp->inst_c1 = sreg;
14200                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14201                                                 }
14202
14203                                                 continue;
14204                                         }
14205
14206                                         g_assert (var->opcode == OP_REGOFFSET);
14207                                                 
14208                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14209
14210                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14211
14212                                         if (vreg_to_lvreg [sreg]) {
14213                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14214
14215                                                 /* The variable is already loaded to an lvreg */
14216                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14217                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14218                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14219                                                 //mono_inst_set_src_registers (ins, sregs);
14220                                                 continue;
14221                                         }
14222
14223                                         /* Try to fuse the load into the instruction */
14224                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
14225                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
14226                                                 sregs [0] = var->inst_basereg;
14227                                                 //mono_inst_set_src_registers (ins, sregs);
14228                                                 ins->inst_offset = var->inst_offset;
14229                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
14230                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
14231                                                 sregs [1] = var->inst_basereg;
14232                                                 //mono_inst_set_src_registers (ins, sregs);
14233                                                 ins->inst_offset = var->inst_offset;
14234                                         } else {
14235                                                 if (MONO_IS_REAL_MOVE (ins)) {
14236                                                         ins->opcode = OP_NOP;
14237                                                         sreg = ins->dreg;
14238                                                 } else {
14239                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14240
14241                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14242
14243                                                         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) {
14244                                                                 if (var->dreg == prev_dreg) {
14245                                                                         /*
14246                                                                          * sreg refers to the value loaded by the load
14247                                                                          * emitted below, but we need to use ins->dreg
14248                                                                          * since it refers to the store emitted earlier.
14249                                                                          */
14250                                                                         sreg = ins->dreg;
14251                                                                 }
14252                                                                 g_assert (sreg != -1);
14253                                                                 vreg_to_lvreg [var->dreg] = sreg;
14254                                                                 g_assert (lvregs_len < 1024);
14255                                                                 lvregs [lvregs_len ++] = var->dreg;
14256                                                         }
14257                                                 }
14258
14259                                                 sregs [srcindex] = sreg;
14260                                                 //mono_inst_set_src_registers (ins, sregs);
14261
14262 #if SIZEOF_REGISTER != 8
14263                                                 if (regtype == 'l') {
14264                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14265                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14266                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14267                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14268                                                         use_ins = load_ins;
14269                                                 }
14270                                                 else
14271 #endif
14272                                                 {
14273 #if SIZEOF_REGISTER == 4
14274                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14275 #endif
14276                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14277                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14278                                                         use_ins = load_ins;
14279                                                 }
14280                                         }
14281
14282                                         if (var->dreg < orig_next_vreg) {
14283                                                 live_range_end [var->dreg] = use_ins;
14284                                                 live_range_end_bb [var->dreg] = bb;
14285                                         }
14286
14287                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14288                                                 MonoInst *tmp;
14289
14290                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14291                                                 tmp->inst_c1 = var->dreg;
14292                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14293                                         }
14294                                 }
14295                         }
14296                         mono_inst_set_src_registers (ins, sregs);
14297
14298                         if (dest_has_lvreg) {
14299                                 g_assert (ins->dreg != -1);
14300                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14301                                 g_assert (lvregs_len < 1024);
14302                                 lvregs [lvregs_len ++] = prev_dreg;
14303                                 dest_has_lvreg = FALSE;
14304                         }
14305
14306                         if (store) {
14307                                 tmp_reg = ins->dreg;
14308                                 ins->dreg = ins->sreg2;
14309                                 ins->sreg2 = tmp_reg;
14310                         }
14311
14312                         if (MONO_IS_CALL (ins)) {
14313                                 /* Clear vreg_to_lvreg array */
14314                                 for (i = 0; i < lvregs_len; i++)
14315                                         vreg_to_lvreg [lvregs [i]] = 0;
14316                                 lvregs_len = 0;
14317                         } else if (ins->opcode == OP_NOP) {
14318                                 ins->dreg = -1;
14319                                 MONO_INST_NULLIFY_SREGS (ins);
14320                         }
14321
14322                         if (cfg->verbose_level > 2)
14323                                 mono_print_ins_index (1, ins);
14324                 }
14325
14326                 /* Extend the live range based on the liveness info */
14327                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14328                         for (i = 0; i < cfg->num_varinfo; i ++) {
14329                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14330
14331                                 if (vreg_is_volatile (cfg, vi->vreg))
14332                                         /* The liveness info is incomplete */
14333                                         continue;
14334
14335                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14336                                         /* Live from at least the first ins of this bb */
14337                                         live_range_start [vi->vreg] = bb->code;
14338                                         live_range_start_bb [vi->vreg] = bb;
14339                                 }
14340
14341                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14342                                         /* Live at least until the last ins of this bb */
14343                                         live_range_end [vi->vreg] = bb->last_ins;
14344                                         live_range_end_bb [vi->vreg] = bb;
14345                                 }
14346                         }
14347                 }
14348         }
14349         
14350 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14351         /*
14352          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14353          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14354          */
14355         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14356                 for (i = 0; i < cfg->num_varinfo; ++i) {
14357                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14358                         MonoInst *ins;
14359
14360                         if (live_range_start [vreg]) {
14361                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14362                                 ins->inst_c0 = i;
14363                                 ins->inst_c1 = vreg;
14364                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14365                         }
14366                         if (live_range_end [vreg]) {
14367                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14368                                 ins->inst_c0 = i;
14369                                 ins->inst_c1 = vreg;
14370                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14371                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14372                                 else
14373                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14374                         }
14375                 }
14376         }
14377 #endif
14378
14379         if (cfg->gsharedvt_locals_var_ins) {
14380                 /* Nullify if unused */
14381                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14382                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14383         }
14384
14385         g_free (live_range_start);
14386         g_free (live_range_end);
14387         g_free (live_range_start_bb);
14388         g_free (live_range_end_bb);
14389 }
14390
14391 /**
14392  * FIXME:
14393  * - use 'iadd' instead of 'int_add'
14394  * - handling ovf opcodes: decompose in method_to_ir.
14395  * - unify iregs/fregs
14396  *   -> partly done, the missing parts are:
14397  *   - a more complete unification would involve unifying the hregs as well, so
14398  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14399  *     would no longer map to the machine hregs, so the code generators would need to
14400  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14401  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14402  *     fp/non-fp branches speeds it up by about 15%.
14403  * - use sext/zext opcodes instead of shifts
14404  * - add OP_ICALL
14405  * - get rid of TEMPLOADs if possible and use vregs instead
14406  * - clean up usage of OP_P/OP_ opcodes
14407  * - cleanup usage of DUMMY_USE
14408  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14409  *   stack
14410  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14411  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14412  * - make sure handle_stack_args () is called before the branch is emitted
14413  * - when the new IR is done, get rid of all unused stuff
14414  * - COMPARE/BEQ as separate instructions or unify them ?
14415  *   - keeping them separate allows specialized compare instructions like
14416  *     compare_imm, compare_membase
14417  *   - most back ends unify fp compare+branch, fp compare+ceq
14418  * - integrate mono_save_args into inline_method
14419  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14420  * - handle long shift opts on 32 bit platforms somehow: they require 
14421  *   3 sregs (2 for arg1 and 1 for arg2)
14422  * - make byref a 'normal' type.
14423  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14424  *   variable if needed.
14425  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14426  *   like inline_method.
14427  * - remove inlining restrictions
14428  * - fix LNEG and enable cfold of INEG
14429  * - generalize x86 optimizations like ldelema as a peephole optimization
14430  * - add store_mem_imm for amd64
14431  * - optimize the loading of the interruption flag in the managed->native wrappers
14432  * - avoid special handling of OP_NOP in passes
14433  * - move code inserting instructions into one function/macro.
14434  * - try a coalescing phase after liveness analysis
14435  * - add float -> vreg conversion + local optimizations on !x86
14436  * - figure out how to handle decomposed branches during optimizations, ie.
14437  *   compare+branch, op_jump_table+op_br etc.
14438  * - promote RuntimeXHandles to vregs
14439  * - vtype cleanups:
14440  *   - add a NEW_VARLOADA_VREG macro
14441  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14442  *   accessing vtype fields.
14443  * - get rid of I8CONST on 64 bit platforms
14444  * - dealing with the increase in code size due to branches created during opcode
14445  *   decomposition:
14446  *   - use extended basic blocks
14447  *     - all parts of the JIT
14448  *     - handle_global_vregs () && local regalloc
14449  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14450  * - sources of increase in code size:
14451  *   - vtypes
14452  *   - long compares
14453  *   - isinst and castclass
14454  *   - lvregs not allocated to global registers even if used multiple times
14455  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14456  *   meaningful.
14457  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14458  * - add all micro optimizations from the old JIT
14459  * - put tree optimizations into the deadce pass
14460  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14461  *   specific function.
14462  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14463  *   fcompare + branchCC.
14464  * - create a helper function for allocating a stack slot, taking into account 
14465  *   MONO_CFG_HAS_SPILLUP.
14466  * - merge r68207.
14467  * - merge the ia64 switch changes.
14468  * - optimize mono_regstate2_alloc_int/float.
14469  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14470  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14471  *   parts of the tree could be separated by other instructions, killing the tree
14472  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14473  *   instructions if the result of the load is used multiple times ?
14474  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14475  * - LAST MERGE: 108395.
14476  * - when returning vtypes in registers, generate IR and append it to the end of the
14477  *   last bb instead of doing it in the epilog.
14478  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14479  */
14480
14481 /*
14482
14483 NOTES
14484 -----
14485
14486 - When to decompose opcodes:
14487   - earlier: this makes some optimizations hard to implement, since the low level IR
14488   no longer contains the neccessary information. But it is easier to do.
14489   - later: harder to implement, enables more optimizations.
14490 - Branches inside bblocks:
14491   - created when decomposing complex opcodes. 
14492     - branches to another bblock: harmless, but not tracked by the branch 
14493       optimizations, so need to branch to a label at the start of the bblock.
14494     - branches to inside the same bblock: very problematic, trips up the local
14495       reg allocator. Can be fixed by spitting the current bblock, but that is a
14496       complex operation, since some local vregs can become global vregs etc.
14497 - Local/global vregs:
14498   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14499     local register allocator.
14500   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14501     structure, created by mono_create_var (). Assigned to hregs or the stack by
14502     the global register allocator.
14503 - When to do optimizations like alu->alu_imm:
14504   - earlier -> saves work later on since the IR will be smaller/simpler
14505   - later -> can work on more instructions
14506 - Handling of valuetypes:
14507   - When a vtype is pushed on the stack, a new temporary is created, an 
14508     instruction computing its address (LDADDR) is emitted and pushed on
14509     the stack. Need to optimize cases when the vtype is used immediately as in
14510     argument passing, stloc etc.
14511 - Instead of the to_end stuff in the old JIT, simply call the function handling
14512   the values on the stack before emitting the last instruction of the bb.
14513 */
14514
14515 #endif /* DISABLE_JIT */